diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8b8e1ee75209..35e61b57754a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -268,8 +268,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast(D); const FunctionDecl *Func = dyn_cast(D); - if ((!Var || !Var->getDeclContext()->isExternCContext()) && - (!Func || !Func->getDeclContext()->isExternCContext())) + if ((!Var || !Var->hasCLanguageLinkage()) && + (!Func || !Func->hasCLanguageLinkage())) return LinkageInfo::uniqueExternal(); } @@ -634,6 +634,31 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const { CachedLinkage = LV.linkage(); CacheValidAndVisibility = LV.visibility() + 1; CachedVisibilityExplicit = LV.visibilityExplicit(); + +#ifndef NDEBUG + // In C (because of gnu inline) and in c++ with microsoft extensions an + // static can follow an extern, so we can have two decls with different + // linkages. + const LangOptions &Opts = getASTContext().getLangOpts(); + if (!Opts.CPlusPlus || Opts.MicrosoftExt) + return LV; + + // We have just computed the linkage for this decl. By induction we know + // that all other computed linkages match, check that the one we just computed + // also does. + NamedDecl *D = NULL; + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + NamedDecl *T = cast(*I); + if (T == this) + continue; + if (T->CacheValidAndVisibility != 0) { + D = T; + break; + } + } + assert(!D || D->CachedLinkage == CachedLinkage); +#endif + return LV; } @@ -772,7 +797,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, bool OnlyTemplate) { // one such matching entity, the program is ill-formed. Otherwise, // if no matching entity is found, the block scope entity receives // external linkage. - if (D->getLexicalDeclContext()->isFunctionOrMethod()) { + if (D->getDeclContext()->isFunctionOrMethod()) { if (const FunctionDecl *Function = dyn_cast(D)) { if (Function->isInAnonymousNamespace() && !Function->getDeclContext()->isExternCContext()) diff --git a/clang/test/SemaCXX/linkage2.cpp b/clang/test/SemaCXX/linkage2.cpp index f6561b9f1256..bab163db2ab4 100644 --- a/clang/test/SemaCXX/linkage2.cpp +++ b/clang/test/SemaCXX/linkage2.cpp @@ -18,3 +18,25 @@ extern "C" { static void test2_f(int x) { // expected-error {{conflicting types for 'test2_f'}} } } + +namespace test3 { + extern "C" { + namespace { + extern int x2; + void f2(); + } + } + namespace { + int x2; + void f2() {} + } +} + +namespace test4 { + void dummy() { + void Bar(); + class A { + friend void Bar(); + }; + } +}