diff options
| author | Fariborz Jahanian <fjahanian@apple.com> | 2010-06-21 16:08:37 +0000 |
|---|---|---|
| committer | Fariborz Jahanian <fjahanian@apple.com> | 2010-06-21 16:08:37 +0000 |
| commit | cc99b3ca9e9a4fba24db1931d07f00dd5045fb4a (patch) | |
| tree | 0da063675568388da954e287bc6321de2ec461d1 | |
| parent | bbc29ea82197eccd2dc17af1bc3174a3f0bcb223 (diff) | |
| download | bcm5719-llvm-cc99b3ca9e9a4fba24db1931d07f00dd5045fb4a.tar.gz bcm5719-llvm-cc99b3ca9e9a4fba24db1931d07f00dd5045fb4a.zip | |
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).
llvm-svn: 106424
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 4 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/internal-linkage.cpp | 37 | ||||
| -rw-r--r-- | clang/test/Sema/var-redecl.c | 4 |
4 files changed, 52 insertions, 3 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 25687e15c4c..c912af878a8 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 528cc65abfc..4a7c877fd98 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/test/CodeGenCXX/internal-linkage.cpp b/clang/test/CodeGenCXX/internal-linkage.cpp index 4263891e57f..9fdb7274e14 100644 --- a/clang/test/CodeGenCXX/internal-linkage.cpp +++ b/clang/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/clang/test/Sema/var-redecl.c b/clang/test/Sema/var-redecl.c index 71d7ea1baee..f7576b6c025 100644 --- a/clang/test/Sema/var-redecl.c +++ b/clang/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}} |

