diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index b482a03299..c0300c50cd 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -708,7 +708,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { // external linkage. if (D->getLexicalDeclContext()->isFunctionOrMethod()) { if (const FunctionDecl *Function = dyn_cast(D)) { - if (Function->isInAnonymousNamespace()) + if (Function->isInAnonymousNamespace() && !Function->isExternC()) return LinkageInfo::uniqueExternal(); LinkageInfo LV; @@ -729,7 +729,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { if (const VarDecl *Var = dyn_cast(D)) if (Var->getStorageClass() == SC_Extern || Var->getStorageClass() == SC_PrivateExtern) { - if (Var->isInAnonymousNamespace()) + if (Var->isInAnonymousNamespace() && !Var->isExternC()) return LinkageInfo::uniqueExternal(); LinkageInfo LV; @@ -1041,8 +1041,11 @@ bool VarDecl::isExternC() const { getStorageClass() != SC_Static) || (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); - DC = DC->getParent()) { + const DeclContext *DC = getDeclContext(); + if (DC->isFunctionOrMethod()) + return false; + + for (; !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) return getStorageClass() != SC_Static; @@ -1050,8 +1053,6 @@ bool VarDecl::isExternC() const { break; } - if (DC->isFunctionOrMethod()) - return false; } return false; @@ -1367,8 +1368,11 @@ bool FunctionDecl::isExternC() const { if (!Context.getLangOptions().CPlusPlus) return getStorageClass() != SC_Static && !getAttr(); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); - DC = DC->getParent()) { + const DeclContext *DC = getDeclContext(); + if (DC->isRecord()) + return false; + + for (; !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) return getStorageClass() != SC_Static && @@ -1376,9 +1380,6 @@ bool FunctionDecl::isExternC() const { break; } - - if (DC->isRecord()) - break; } return isMain(); diff --git a/test/SemaCXX/linkage.cpp b/test/SemaCXX/linkage.cpp index b93a310b00..6b73d596e0 100644 --- a/test/SemaCXX/linkage.cpp +++ b/test/SemaCXX/linkage.cpp @@ -3,7 +3,7 @@ // compared against the earlier cached value. If we had a way of // testing linkage directly in Sema, that would be better. -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -Werror -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s // PR8926 namespace test0 { @@ -69,5 +69,28 @@ namespace { extern "C" void test4(void) {} } +// PR9316: Ensure that even non-namespace-scope function declarations in +// a C declaration context respect that over the anonymous namespace. +extern "C" { + namespace { + struct X { + int f() { + extern int g(); + extern int a; + + // Test both for mangling in the code generation and warnings from use + // of internal, undefined names via -Werror. + // CHECK: call i32 @g( + // CHECK: load i32* @a, + return g() + a; + } + }; + } + // Force the above function to be emitted by codegen. + int test(X& x) { + return x.f(); + } +} + // CHECK: define linkonce_odr i8* @_ZN5test21A1BILj0EE3fooEv( // CHECK: define linkonce_odr i8* @_ZN5test11A3fooILj0EEEPvv(