From: Richard Smith Date: Tue, 18 Jun 2013 20:15:12 +0000 (+0000) Subject: DR14, DR101, and part of DR1: fix handling of extern "C" declarations in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=662f41bd9d4bfb4aebaba05e6043a6ff5f0dc2ff;p=clang DR14, DR101, and part of DR1: fix handling of extern "C" declarations in namespaces, by treating them just like we treat extern "C" declarations in function scope. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184223 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ca20c04fa6..f67e95c393 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -341,8 +341,7 @@ public: llvm::DenseMap LocallyScopedExternCDecls; /// \brief Look for a locally scoped extern "C" declaration by the given name. - llvm::DenseMap::iterator - findLocallyScopedExternCDecl(DeclarationName Name); + NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); typedef LazyVector @@ -1408,9 +1407,7 @@ public: NamedDecl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists); - void RegisterLocallyScopedExternCDecl(NamedDecl *ND, - const LookupResult &Previous, - Scope *S); + void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e62834ba1d..418a70a8ba 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4354,21 +4354,22 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, } /// \brief Register the given locally-scoped extern "C" declaration so -/// that it can be found later for redeclarations +/// that it can be found later for redeclarations. We include any extern "C" +/// declaration that is not visible in the translation unit here, not just +/// function-scope declarations. void -Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, - const LookupResult &Previous, - Scope *S) { - assert(ND->getLexicalDeclContext()->isFunctionOrMethod() && - "Decl is not a locally-scoped decl!"); +Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) { + assert( + !ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit() && + "Decl is not a locally-scoped decl!"); // Note that we have a locally-scoped external with this name. LocallyScopedExternCDecls[ND->getDeclName()] = ND; } -llvm::DenseMap::iterator -Sema::findLocallyScopedExternCDecl(DeclarationName Name) { +NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) { if (ExternalSource) { // Load locally-scoped external decls from the external source. + // FIXME: This is inefficient. Maybe add a DeclContext for extern "C" decls? SmallVector Decls; ExternalSource->ReadLocallyScopedExternCDecls(Decls); for (unsigned I = 0, N = Decls.size(); I != N; ++I) { @@ -4378,8 +4379,9 @@ Sema::findLocallyScopedExternCDecl(DeclarationName Name) { LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I]; } } - - return LocallyScopedExternCDecls.find(Name); + + NamedDecl *D = LocallyScopedExternCDecls.lookup(Name); + return D ? cast(D->getMostRecentDecl()) : 0; } /// \brief Diagnose function specifiers on a declaration of an identifier that @@ -5048,11 +5050,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, ProcessPragmaWeak(S, NewVD); checkAttributesAfterMerging(*this, *NewVD); - // If this is a locally-scoped extern C variable, update the map of - // such variables. - if (CurContext->isFunctionOrMethod() && NewVD->isExternC() && - !NewVD->isInvalidDecl()) - RegisterLocallyScopedExternCDecl(NewVD, Previous, S); + // If this is the first declaration of an extern C variable that is not + // declared directly in the translation unit, update the map of such + // variables. + if (!CurContext->getRedeclContext()->isTranslationUnit() && + !NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() && + // FIXME: We only check isExternC if we're in an extern C context, + // to avoid computing and caching an 'externally visible' flag which + // could change if the variable's type is not visible. + (!getLangOpts().CPlusPlus || NewVD->isInExternCContext()) && + NewVD->isExternC()) + RegisterLocallyScopedExternCDecl(NewVD, S); return NewVD; } @@ -5360,10 +5368,9 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, // not in scope. bool PreviousWasHidden = false; if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) { - llvm::DenseMap::iterator Pos - = findLocallyScopedExternCDecl(NewVD->getDeclName()); - if (Pos != LocallyScopedExternCDecls.end()) { - Previous.addDecl(Pos->second); + if (NamedDecl *ExternCPrev = + findLocallyScopedExternCDecl(NewVD->getDeclName())) { + Previous.addDecl(ExternCPrev); PreviousWasHidden = true; } } @@ -6598,11 +6605,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // marking the function. AddCFAuditedAttribute(NewFD); - // If this is a locally-scoped extern C function, update the - // map of such names. - if (CurContext->isFunctionOrMethod() && NewFD->isExternC() - && !NewFD->isInvalidDecl()) - RegisterLocallyScopedExternCDecl(NewFD, Previous, S); + // If this is the first declaration of an extern C variable that is not + // declared directly in the translation unit, update the map of such + // variables. + if (!CurContext->getRedeclContext()->isTranslationUnit() && + !NewFD->getPreviousDecl() && NewFD->isExternC() && + !NewFD->isInvalidDecl()) + RegisterLocallyScopedExternCDecl(NewFD, S); // Set this FunctionDecl's range up to the right paren. NewFD->setRangeEnd(D.getSourceRange().getEnd()); @@ -6709,10 +6718,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) { // Since we did not find anything by this name, look for a non-visible // extern "C" declaration with the same name. - llvm::DenseMap::iterator Pos - = findLocallyScopedExternCDecl(NewFD->getDeclName()); - if (Pos != LocallyScopedExternCDecls.end()) - Previous.addDecl(Pos->second); + if (NamedDecl *ExternCPrev = + findLocallyScopedExternCDecl(NewFD->getDeclName())) + Previous.addDecl(ExternCPrev); } // Filter out any non-conflicting previous declarations. @@ -9063,12 +9071,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // function, see whether there was a locally-scoped declaration of // this name as a function or variable. If so, use that // (non-visible) declaration, and complain about it. - llvm::DenseMap::iterator Pos - = findLocallyScopedExternCDecl(&II); - if (Pos != LocallyScopedExternCDecls.end()) { - Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second; - Diag(Pos->second->getLocation(), diag::note_previous_declaration); - return Pos->second; + if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) { + Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev; + Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); + return ExternCPrev; } // Extension in C99. Legal in C90, but warn about it. diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp index 5a65fca841..9af1656d43 100644 --- a/test/CXX/drs/dr0xx.cpp +++ b/test/CXX/drs/dr0xx.cpp @@ -3,19 +3,19 @@ // RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors namespace dr1 { // dr1: no - namespace X { extern "C" void dr1_f(int a = 1); } // expected-note 2{{candidate}} expected-note {{conflicting}} - namespace Y { extern "C" void dr1_f(int a = 2); } // expected-note 2{{candidate}} expected-note {{target}} + namespace X { extern "C" void dr1_f(int a = 1); } + namespace Y { extern "C" void dr1_f(int a = 2); } using X::dr1_f; using Y::dr1_f; void g() { - // FIXME: The first of these two should be accepted. - dr1_f(0); // expected-error {{ambiguous}} - dr1_f(); // expected-error {{ambiguous}} + dr1_f(0); + // FIXME: This should be rejected, due to the ambiguous default argument. + dr1_f(); } namespace X { - using Y::dr1_f; // expected-error {{conflicts with declaration already in scope}} + using Y::dr1_f; void h() { - // FIXME: The second of these two should be rejected. dr1_f(0); + // FIXME: This should be rejected, due to the ambiguous default argument. dr1_f(); } } @@ -129,22 +129,19 @@ namespace dr12 { // dr12: sup 239 } } -namespace dr14 { // dr14: no - namespace X { extern "C" int dr14_f(); } // expected-note {{candidate}} - namespace Y { extern "C" int dr14_f(); } // expected-note {{candidate}} +namespace dr14 { // dr14: yes + namespace X { extern "C" int dr14_f(); } + namespace Y { extern "C" int dr14_f(); } using namespace X; using namespace Y; - // FIXME: This should be accepted, name lookup only finds one function (in two - // different namespaces). - int k = dr14_f(); // expected-error {{ambiguous}} + int k = dr14_f(); class C { - int k; // expected-note {{here}} + int k; friend int Y::dr14_f(); } c; namespace Z { - // FIXME: This should be accepted, this function is a friend. - extern "C" int dr14_f() { return c.k; } // expected-error {{private}} + extern "C" int dr14_f() { return c.k; } } namespace X { typedef int T; typedef int U; } // expected-note {{candidate}} diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp index ab90168924..7d5b36d922 100644 --- a/test/CXX/drs/dr1xx.cpp +++ b/test/CXX/drs/dr1xx.cpp @@ -9,15 +9,14 @@ namespace dr100 { // dr100: yes B<"bar"> b; // expected-error {{does not refer to any declaration}} } -namespace dr101 { // dr101: no - // FIXME: This is valid. - extern "C" void dr101_f(); // expected-note {{conflicting declaration}} +namespace dr101 { // dr101: yes + extern "C" void dr101_f(); typedef unsigned size_t; namespace X { - extern "C" void dr101_f(); // expected-note {{target of using declaration}} + extern "C" void dr101_f(); typedef unsigned size_t; } - using X::dr101_f; // expected-error {{conflicts with declaration already in scope}} + using X::dr101_f; using X::size_t; } diff --git a/test/SemaCXX/PR10447.cpp b/test/SemaCXX/PR10447.cpp index 5ba74aaba3..0c57177b87 100644 --- a/test/SemaCXX/PR10447.cpp +++ b/test/SemaCXX/PR10447.cpp @@ -4,7 +4,7 @@ // PR12223 namespace test1 { namespace N { - extern "C" void f(struct S*); + extern "C" void f_test1(struct S*); void g(S*); } namespace N { @@ -17,7 +17,7 @@ namespace test1 { // PR10447 namespace test2 { extern "C" { - void f(struct Bar*) { } + void f_test2(struct Bar*) { } test2::Bar *ptr; } } diff --git a/test/SemaCXX/extern-c.cpp b/test/SemaCXX/extern-c.cpp index c55b10d9d6..220b2a8dc1 100644 --- a/test/SemaCXX/extern-c.cpp +++ b/test/SemaCXX/extern-c.cpp @@ -2,7 +2,7 @@ namespace test1 { extern "C" { - void f() { + void test1_f() { void test1_g(int); // expected-note {{previous declaration is here}} } } @@ -11,7 +11,7 @@ int test1_g(int); // expected-error {{functions that differ only in their return namespace test2 { extern "C" { - void f() { + void test2_f() { extern int test2_x; // expected-note {{previous definition is here}} } } @@ -20,7 +20,7 @@ float test2_x; // expected-error {{redefinition of 'test2_x' with a different ty namespace test3 { extern "C" { - void f() { + void test3_f() { extern int test3_b; // expected-note {{previous definition is here}} } } @@ -56,3 +56,53 @@ namespace foo { extern float test6_b; } } + +namespace linkage { + namespace redecl { + extern "C" { + static void linkage_redecl(); + static void linkage_redecl(int); + void linkage_redecl(); // ok, still not extern "C" + void linkage_redecl(int); // ok, still not extern "C" + void linkage_redecl(float); // expected-note {{previous}} + void linkage_redecl(double); // expected-error {{conflicting types}} + } + } + namespace from_outer { + void linkage_from_outer_1(); + void linkage_from_outer_2(); // expected-note {{previous}} + extern "C" { + void linkage_from_outer_1(int); // expected-note {{previous}} + void linkage_from_outer_1(); // expected-error {{conflicting types}} + void linkage_from_outer_2(); // expected-error {{different language linkage}} + } + } + namespace mixed { + extern "C" { + void linkage_mixed_1(); + static void linkage_mixed_1(int); + + static void linkage_mixed_2(int); + void linkage_mixed_2(); + } + } + namespace across_scopes { + namespace X { + extern "C" void linkage_across_scopes_f() { + void linkage_across_scopes_g(); // expected-note {{previous}} + } + } + namespace Y { + extern "C" void linkage_across_scopes_g(int); // expected-error {{conflicting}} + } + } +} + +void lookup_in_global_f(); +namespace lookup_in_global { + void lookup_in_global_f(); + extern "C" { + // FIXME: We should reject this. + void lookup_in_global_f(int); + } +} diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index 19fe637d65..eda94fb38a 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -122,7 +122,7 @@ 14 NAD extern "C" functions and declarations in different namespaces - No + Yes 15 @@ -644,7 +644,7 @@ 101 TC1 Redeclaration of extern "C" names via using-declarations - No + Yes 102