aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Decl.cpp10
-rw-r--r--lib/Sema/SemaDecl.cpp4
-rw-r--r--test/CodeGenCXX/internal-linkage.cpp37
-rw-r--r--test/Sema/var-redecl.c4
4 files changed, 52 insertions, 3 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 25687e15c4..c912af878a 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -701,7 +701,15 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
// AST for 'extern "C" int foo;' is annotated with 'extern'.
if (hasExternalStorage())
return DeclarationOnly;
-
+
+ if (getStorageClassAsWritten() == Extern ||
+ getStorageClassAsWritten() == PrivateExtern) {
+ for (const VarDecl *PrevVar = getPreviousDeclaration();
+ PrevVar; PrevVar = PrevVar->getPreviousDeclaration()) {
+ if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit())
+ return DeclarationOnly;
+ }
+ }
// C99 6.9.2p2:
// A declaration of an object that has file scope without an initializer,
// and without a storage class specifier or the scs 'static', constitutes
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 528cc65abf..4a7c877fd9 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1455,6 +1455,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return;
}
+ if (New->hasExternalStorage() &&
+ Old->getLinkage() == InternalLinkage)
+ New->setStorageClass(Old->getStorageClass());
+
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
diff --git a/test/CodeGenCXX/internal-linkage.cpp b/test/CodeGenCXX/internal-linkage.cpp
index 4263891e57..9fdb7274e1 100644
--- a/test/CodeGenCXX/internal-linkage.cpp
+++ b/test/CodeGenCXX/internal-linkage.cpp
@@ -17,3 +17,40 @@ Anon anon1;
// CHECK: @anon2 = internal global
X<Anon> anon2;
+// rdar: // 8071804
+char const * const xyzzy = "Hello, world!";
+extern char const * const xyzzy;
+
+char const * const *test1()
+{
+ // CHECK: @_ZL5xyzzy = internal constant
+ return &xyzzy;
+}
+
+static char const * const static_xyzzy = "Hello, world!";
+extern char const * const static_xyzzy;
+
+char const * const *test2()
+{
+ // CHECK: @_ZL12static_xyzzy = internal constant
+ return &static_xyzzy;
+}
+
+static char const * static_nonconst_xyzzy = "Hello, world!";
+extern char const * static_nonconst_xyzzy;
+
+char const * *test3()
+{
+ // CHECK: @_ZL21static_nonconst_xyzzy = internal global
+ return &static_nonconst_xyzzy;
+}
+
+
+char const * extern_nonconst_xyzzy = "Hello, world!";
+extern char const * extern_nonconst_xyzzy;
+
+char const * *test4()
+{
+ // CHECK: @extern_nonconst_xyzzy = global
+ return &extern_nonconst_xyzzy;
+}
diff --git a/test/Sema/var-redecl.c b/test/Sema/var-redecl.c
index 71d7ea1bae..f7576b6c02 100644
--- a/test/Sema/var-redecl.c
+++ b/test/Sema/var-redecl.c
@@ -58,5 +58,5 @@ int *p=&g19; // expected-error{{use of undeclared identifier 'g19'}} \
// PR3645
static int a;
-extern int a;
-int a;
+extern int a; // expected-note {{previous definition is here}}
+int a; // expected-error {{non-static declaration of 'a' follows static declaration}}