From: Fariborz Jahanian Date: Mon, 21 Jun 2010 16:08:37 +0000 (+0000) Subject: Fixes a corner case bug whereby declaring and defining an extern variable in a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2bf6d7b1f7406ca4dfe841d4f6ef4b91dce195e4;p=clang Fixes a corner case bug whereby declaring and defining an extern variable in a particular sequence causes its definition to not be generated in the object file. (fixes radar 8071804). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106424 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 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}}