llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternCDecls;
/// \brief Look for a locally scoped extern "C" declaration by the given name.
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- findLocallyScopedExternCDecl(DeclarationName Name);
+ NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name);
typedef LazyVector<VarDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadTentativeDefinitions, 2, 2>
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,
}
/// \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<DeclarationName, NamedDecl *>::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<NamedDecl *, 4> Decls;
ExternalSource->ReadLocallyScopedExternCDecls(Decls);
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I];
}
}
-
- return LocallyScopedExternCDecls.find(Name);
+
+ NamedDecl *D = LocallyScopedExternCDecls.lookup(Name);
+ return D ? cast<NamedDecl>(D->getMostRecentDecl()) : 0;
}
/// \brief Diagnose function specifiers on a declaration of an identifier that
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;
}
// not in scope.
bool PreviousWasHidden = false;
if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternCDecl(NewVD->getDeclName());
- if (Pos != LocallyScopedExternCDecls.end()) {
- Previous.addDecl(Pos->second);
+ if (NamedDecl *ExternCPrev =
+ findLocallyScopedExternCDecl(NewVD->getDeclName())) {
+ Previous.addDecl(ExternCPrev);
PreviousWasHidden = true;
}
}
// 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());
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<DeclarationName, NamedDecl *>::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.
// 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<DeclarationName, NamedDecl *>::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.
// 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();
}
}
}
}
-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}}
namespace test1 {
extern "C" {
- void f() {
+ void test1_f() {
void test1_g(int); // expected-note {{previous declaration is here}}
}
}
namespace test2 {
extern "C" {
- void f() {
+ void test2_f() {
extern int test2_x; // expected-note {{previous definition is here}}
}
}
namespace test3 {
extern "C" {
- void f() {
+ void test3_f() {
extern int test3_b; // expected-note {{previous definition is here}}
}
}
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);
+ }
+}