diff options
-rw-r--r-- | clang/lib/AST/Decl.cpp | 12 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 8 | ||||
-rw-r--r-- | clang/test/CXX/basic/basic.link/p8.cpp | 7 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr11xx.cpp | 30 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/anonymous-namespaces.cpp | 9 | ||||
-rw-r--r-- | clang/test/SemaCXX/linkage2.cpp | 5 | ||||
-rw-r--r-- | clang/test/SemaCXX/undefined-internal.cpp | 8 |
7 files changed, 69 insertions, 10 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 19fbf878e7e..3f9eaf28ef9 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -619,16 +619,16 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, if (D->isInAnonymousNamespace()) { const auto *Var = dyn_cast<VarDecl>(D); const auto *Func = dyn_cast<FunctionDecl>(D); - // FIXME: In C++11 onwards, anonymous namespaces should give decls - // within them (including those inside extern "C" contexts) internal - // linkage, not unique external linkage: + // FIXME: The check for extern "C" here is not justified by the standard + // wording, but we retain it from the pre-DR1113 model to avoid breaking + // code. // // C++11 [basic.link]p4: // An unnamed namespace or a namespace declared directly or indirectly // within an unnamed namespace has internal linkage. if ((!Var || !isFirstInExternCContext(Var)) && (!Func || !isFirstInExternCContext(Func))) - return LinkageInfo::uniqueExternal(); + return getInternalLinkageFor(D); } // Set up the defaults. @@ -1130,7 +1130,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, if (const auto *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace() && !Function->isInExternCContext()) - return LinkageInfo::uniqueExternal(); + return getInternalLinkageFor(Function); // This is a "void f();" which got merged with a file static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) @@ -1153,7 +1153,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, if (const auto *Var = dyn_cast<VarDecl>(D)) { if (Var->hasExternalStorage()) { if (Var->isInAnonymousNamespace() && !Var->isInExternCContext()) - return LinkageInfo::uniqueExternal(); + return getInternalLinkageFor(Var); LinkageInfo LV; if (Var->getStorageClass() == SC_PrivateExtern) diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5ce52171562..8c5ebd0113a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1287,9 +1287,15 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // // void test() { extern void foo(); } // static void foo(); + // + // Don't bother with the L marker for names in anonymous namespaces; the + // 12_GLOBAL__N_1 mangling is quite sufficient there, and this better + // matches GCC anyway, because GCC does not treat anonymous namespaces as + // implying internal linkage. if (ND && ND->getFormalLinkage() == InternalLinkage && !ND->isExternallyVisible() && - getEffectiveDeclContext(ND)->isFileContext()) + getEffectiveDeclContext(ND)->isFileContext() && + !ND->isInAnonymousNamespace()) Out << 'L'; auto *FD = dyn_cast<FunctionDecl>(ND); diff --git a/clang/test/CXX/basic/basic.link/p8.cpp b/clang/test/CXX/basic/basic.link/p8.cpp index 07adc65b67a..317fb31fb03 100644 --- a/clang/test/CXX/basic/basic.link/p8.cpp +++ b/clang/test/CXX/basic/basic.link/p8.cpp @@ -52,6 +52,13 @@ void use_visible_no_linkage() { visible_no_linkage3(); // expected-note {{used here}} } +namespace { + struct InternalLinkage {}; +} +InternalLinkage internal_linkage(); // expected-error {{used but not defined}} +void use_internal_linkage() { + internal_linkage(); // expected-note {{used here}} +} extern inline int not_defined; // expected-error {{not defined}} extern inline int defined_after_use; diff --git a/clang/test/CXX/drs/dr11xx.cpp b/clang/test/CXX/drs/dr11xx.cpp new file mode 100644 index 00000000000..81fbc1e3ef1 --- /dev/null +++ b/clang/test/CXX/drs/dr11xx.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors + +namespace dr1113 { // dr1113: partial + namespace named { + extern int a; // expected-note {{previous}} + static int a; // expected-error {{static declaration of 'a' follows non-static}} + } + namespace { + extern int a; + static int a; // ok, both declarations have internal linkage + int b = a; + } + + // FIXME: Per DR1113 and DR4, this is ill-formed due to ambiguity: the second + // 'f' has internal linkage, and so does not have C language linkage, so is + // not a redeclaration of the first 'f'. + // + // To avoid a breaking change here, Clang ignores the "internal linkage" effect + // of anonymous namespaces on declarations declared within an 'extern "C"' + // linkage-specification. + extern "C" void f(); + namespace { + extern "C" void f(); + } + void g() { f(); } +} diff --git a/clang/test/CodeGenCXX/anonymous-namespaces.cpp b/clang/test/CodeGenCXX/anonymous-namespaces.cpp index abc700fef6c..b2857ff4171 100644 --- a/clang/test/CodeGenCXX/anonymous-namespaces.cpp +++ b/clang/test/CodeGenCXX/anonymous-namespaces.cpp @@ -6,7 +6,8 @@ int f(); namespace { // CHECK-1: @_ZN12_GLOBAL__N_11bE = internal global i32 0 - // CHECK-1: @_ZN12_GLOBAL__N_1L1cE = internal global i32 0 + // CHECK-1: @_ZN12_GLOBAL__N_11cE = internal global i32 0 + // CHECK-1: @_ZN12_GLOBAL__N_12c2E = internal global i32 0 // CHECK-1: @_ZN12_GLOBAL__N_11D1dE = internal global i32 0 // CHECK-1: @_ZN12_GLOBAL__N_11aE = internal global i32 0 int a = 0; @@ -15,6 +16,12 @@ namespace { static int c = f(); + // Note, we can't use an 'L' mangling for c or c2 (like GCC does) based on + // the 'static' specifier, because the variable can be redeclared without it. + extern int c2; + int g() { return c2; } + static int c2 = f(); + class D { static int d; }; diff --git a/clang/test/SemaCXX/linkage2.cpp b/clang/test/SemaCXX/linkage2.cpp index a7eb15f7c6b..8c80f4bdb90 100644 --- a/clang/test/SemaCXX/linkage2.cpp +++ b/clang/test/SemaCXX/linkage2.cpp @@ -143,9 +143,10 @@ namespace test13 { } namespace test14 { + // Anonymous namespace implies internal linkage, so 'static' has no effect. namespace { - void a(void); // expected-note {{previous declaration is here}} - static void a(void) {} // expected-error {{static declaration of 'a' follows non-static declaration}} + void a(void); + static void a(void) {} } } diff --git a/clang/test/SemaCXX/undefined-internal.cpp b/clang/test/SemaCXX/undefined-internal.cpp index 32151b71ea1..60fa202384d 100644 --- a/clang/test/SemaCXX/undefined-internal.cpp +++ b/clang/test/SemaCXX/undefined-internal.cpp @@ -187,6 +187,10 @@ namespace OverloadUse { void f(); void f(int); // expected-warning {{function 'OverloadUse::(anonymous namespace)::f' has internal linkage but is not defined}} void f(int, int); // expected-warning {{function 'OverloadUse::(anonymous namespace)::f' has internal linkage but is not defined}} +#if __cplusplus < 201103L + // expected-note@-3 {{here}} + // expected-note@-3 {{here}} +#endif } template<void x()> void t() { x(); } template<void x(int)> void t(int*) { x(10); } @@ -194,6 +198,10 @@ namespace OverloadUse { void g(int n) { t<f>(&n); // expected-note {{used here}} t<f>(&n, &n); // expected-note {{used here}} +#if __cplusplus < 201103L + // expected-warning@-3 {{non-type template argument referring to function 'f' with internal linkage}} + // expected-warning@-3 {{non-type template argument referring to function 'f' with internal linkage}} +#endif } } |