summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/Decl.cpp12
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp8
-rw-r--r--clang/test/CXX/basic/basic.link/p8.cpp7
-rw-r--r--clang/test/CXX/drs/dr11xx.cpp30
-rw-r--r--clang/test/CodeGenCXX/anonymous-namespaces.cpp9
-rw-r--r--clang/test/SemaCXX/linkage2.cpp5
-rw-r--r--clang/test/SemaCXX/undefined-internal.cpp8
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
}
}
OpenPOWER on IntegriCloud