r178488 - Only merge down a variable type if the previous declaration was
John McCall
rjmccall at apple.com
Mon Apr 1 11:34:28 PDT 2013
Author: rjmccall
Date: Mon Apr 1 13:34:28 2013
New Revision: 178488
URL: http://llvm.org/viewvc/llvm-project?rev=178488&view=rev
Log:
Only merge down a variable type if the previous declaration was
visible. There's a lot of potential badness in how we're modelling
these things, but getting this much correct is reasonably easy.
rdar://13535367
Added:
cfe/trunk/test/CXX/basic/basic.link/p6.cpp
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Sema/extern-redecl.c
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=178488&r1=178487&r2=178488&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Apr 1 13:34:28 2013
@@ -1759,8 +1759,9 @@ public:
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
Scope *S);
void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
- void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
- void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+ void MergeVarDecl(VarDecl *New, LookupResult &OldDecls,
+ bool OldDeclsWereHidden);
+ void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldIsHidden);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=178488&r1=178487&r2=178488&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Apr 1 13:34:28 2013
@@ -2773,7 +2773,7 @@ void Sema::mergeObjCMethodDecls(ObjCMeth
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
/// to here in AddInitializerToDecl. We can't check them before the initializer
/// is attached.
-void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
+void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
if (New->isInvalidDecl() || Old->isInvalidDecl())
return;
@@ -2820,7 +2820,11 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- New->setType(MergedT);
+
+ // Don't actually update the type on the new declaration if the old
+ // declaration was a extern declaration in a different scope.
+ if (!OldWasHidden)
+ New->setType(MergedT);
}
/// MergeVarDecl - We just parsed a variable 'New' which has the same name
@@ -2831,7 +2835,8 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne
/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
/// definitions here, since the initializer hasn't been attached.
///
-void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
+void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
+ bool PreviousWasHidden) {
// If the new decl is already invalid, don't do any other checking.
if (New->isInvalidDecl())
return;
@@ -2871,7 +2876,7 @@ void Sema::MergeVarDecl(VarDecl *New, Lo
}
// Merge the types.
- MergeVarDeclTypes(New, Old);
+ MergeVarDeclTypes(New, Old, PreviousWasHidden);
if (New->isInvalidDecl())
return;
@@ -5206,13 +5211,39 @@ bool Sema::CheckVariableDeclaration(VarD
NewVD->setTypeSourceInfo(FixedTInfo);
}
+ // If we did not find anything by this name, look for a non-visible
+ // extern "C" declaration with the same name.
+ //
+ // Clang has a lot of problems with extern local declarations.
+ // The actual standards text here is:
+ //
+ // C++11 [basic.link]p6:
+ // The name of a function declared in block scope and the name
+ // of a variable declared by a block scope extern declaration
+ // have linkage. If there is a visible declaration of an entity
+ // with linkage having the same name and type, ignoring entities
+ // declared outside the innermost enclosing namespace scope, the
+ // block scope declaration declares that same entity and
+ // receives the linkage of the previous declaration.
+ //
+ // C11 6.2.7p4:
+ // For an identifier with internal or external linkage declared
+ // in a scope in which a prior declaration of that identifier is
+ // visible, if the prior declaration specifies internal or
+ // external linkage, the type of the identifier at the later
+ // declaration becomes the composite type.
+ //
+ // The most important point here is that we're not allowed to
+ // update our understanding of the type according to declarations
+ // not in scope.
+ bool PreviousWasHidden = false;
if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
- // Since we did not find anything by this name, look for a non-visible
- // extern "C" declaration with the same name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
= findLocallyScopedExternCDecl(NewVD->getDeclName());
- if (Pos != LocallyScopedExternCDecls.end())
+ if (Pos != LocallyScopedExternCDecls.end()) {
Previous.addDecl(Pos->second);
+ PreviousWasHidden = true;
+ }
}
// Filter out any non-conflicting previous declarations.
@@ -5245,7 +5276,7 @@ bool Sema::CheckVariableDeclaration(VarD
}
if (!Previous.empty()) {
- MergeVarDecl(NewVD, Previous);
+ MergeVarDecl(NewVD, Previous, PreviousWasHidden);
return true;
}
return false;
@@ -7277,7 +7308,7 @@ void Sema::AddInitializerToDecl(Decl *Re
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl())
- MergeVarDeclTypes(VDecl, Old);
+ MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
}
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
Added: cfe/trunk/test/CXX/basic/basic.link/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.link/p6.cpp?rev=178488&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.link/p6.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.link/p6.cpp Mon Apr 1 13:34:28 2013
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++11 [basic.link]p6:
+// The name of a function declared in block scope and the name
+// of a variable declared by a block scope extern declaration
+// have linkage. If there is a visible declaration of an entity
+// with linkage having the same name and type, ignoring entities
+// declared outside the innermost enclosing namespace scope, the
+// block scope declaration declares that same entity and
+// receives the linkage of the previous declaration.
+
+// rdar://13535367
+namespace test0 {
+ extern "C" int test0_array[];
+ void declare() { extern int test0_array[100]; }
+ extern "C" int test0_array[];
+ int value = sizeof(test0_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test1 {
+ extern "C" int test1_array[];
+ void test() {
+ { extern int test1_array[100]; }
+ extern int test1_array[];
+ int x = sizeof(test1_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+}
+
+namespace test2 {
+ void declare() { extern int test2_array[100]; }
+ extern int test2_array[];
+ int value = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test3 {
+ void test() {
+ { extern int test3_array[100]; }
+ extern int test3_array[];
+ int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+}
+
+
Modified: cfe/trunk/test/Sema/extern-redecl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/extern-redecl.c?rev=178488&r1=178487&r2=178488&view=diff
==============================================================================
--- cfe/trunk/test/Sema/extern-redecl.c (original)
+++ cfe/trunk/test/Sema/extern-redecl.c Mon Apr 1 13:34:28 2013
@@ -22,3 +22,14 @@ int PR10013(void) {
static int test1_a[]; // expected-warning {{tentative array definition assumed to have one element}}
extern int test1_a[];
+
+// rdar://13535367
+void test2declarer() { extern int test2_array[100]; }
+extern int test2_array[];
+int test2v = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+
+void test3declarer() {
+ { extern int test3_array[100]; }
+ extern int test3_array[];
+ int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
More information about the cfe-commits
mailing list