aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTConsumer.h12
-rw-r--r--lib/AST/Decl.cpp3
-rw-r--r--lib/CodeGen/CodeGenModule.cpp27
-rw-r--r--lib/CodeGen/CodeGenModule.h11
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp7
-rw-r--r--lib/Sema/Sema.cpp65
-rw-r--r--lib/Sema/Sema.h8
-rw-r--r--lib/Sema/SemaDecl.cpp17
-rw-r--r--test/PCH/external-defs.h3
-rw-r--r--test/Sema/init.c3
-rw-r--r--test/Sema/tentative-decls.c6
-rw-r--r--tools/clang-cc/Backend.cpp4
12 files changed, 103 insertions, 63 deletions
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index fd79bf59ea..6dc7e13d8f 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -20,6 +20,7 @@ namespace clang {
class TagDecl;
class HandleTagDeclDefinition;
class SemaConsumer; // layering violation required for safe SemaConsumer
+ class VarDecl;
/// ASTConsumer - This is an abstract interface that should be implemented by
/// clients that read ASTs. This abstraction layer allows the client to be
@@ -56,6 +57,17 @@ public:
/// can be defined in declspecs).
virtual void HandleTagDeclDefinition(TagDecl *D) {}
+ /// \brief Callback invoked at the end of a translation unit to
+ /// notify the consumer that the given tentative definition should
+ /// be completed.
+ ///
+ /// The variable declaration itself will be a tentative
+ /// definition. If it had an incomplete array type, its type will
+ /// have already been changed to an array of size 1. However, the
+ /// declaration remains a tentative definition and has not been
+ /// modified by the introduction of an implicit zero initializer.
+ virtual void CompleteTentativeDefinition(VarDecl *D) {}
+
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 8bda32398f..0326b34960 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -291,7 +291,8 @@ bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
return false;
- return (!getInit() &&
+ const VarDecl *Def = 0;
+ return (!getDefinition(Def) &&
(getStorageClass() == None || getStorageClass() == Static));
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 0526e7845c..9ae93599df 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -424,13 +424,6 @@ void CodeGenModule::EmitDeferred() {
// Otherwise, emit the definition and move on to the next one.
EmitGlobalDefinition(D);
}
-
- // Emit any tentative definitions, in reverse order so the most
- // important (merged) decl will be seen and emitted first.
- for (std::vector<const VarDecl*>::reverse_iterator
- it = TentativeDefinitions.rbegin(), ie = TentativeDefinitions.rend();
- it != ie; ++it)
- EmitTentativeDefinition(*it);
}
/// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the
@@ -502,6 +495,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Invalid decl");
+
return VD->getStorageClass() == VarDecl::Static;
}
@@ -520,16 +514,14 @@ void CodeGenModule::EmitGlobal(const ValueDecl *Global) {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- // If this isn't a definition, defer code generation.
- if (!VD->getInit()) {
- // If this is a tentative definition, remember it so that we can
- // emit the common definition if needed. It is important to
- // defer tentative definitions, since they may have incomplete
- // type.
- if (!VD->hasExternalStorage())
- TentativeDefinitions.push_back(VD);
+ // In C++, if this is marked "extern", defer code generation.
+ if (getLangOptions().CPlusPlus &&
+ VD->getStorageClass() == VarDecl::Extern && !VD->getInit())
+ return;
+
+ // In C, if this isn't a definition, defer code generation.
+ if (!getLangOptions().CPlusPlus && !VD->getInit())
return;
- }
}
// Defer code generation when possible if this is a static definition, inline
@@ -727,6 +719,9 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
// See if we have already defined this (as a variable), if so we do
// not need to do anything.
llvm::GlobalValue *GV = GlobalDeclMap[getMangledName(D)];
+ if (!GV && MayDeferGeneration(D)) // this variable was never referenced
+ return;
+
if (llvm::GlobalVariable *Var = dyn_cast_or_null<llvm::GlobalVariable>(GV))
if (Var->hasInitializer())
return;
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index e7924fade5..21ef8da863 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -119,14 +119,6 @@ class CodeGenModule : public BlockModule {
/// is done.
std::vector<const ValueDecl*> DeferredDeclsToEmit;
- /// TentativeDefinitions - A list of declarations which are
- /// tentative definitions. Code generation for these must be
- /// deferred because they are allowed to have incomplete type when
- /// they are seen. This also allows us to avoid generating an extra
- /// common definiton in situations where the tentative definition is
- /// followed by an actual definition.
- std::vector<const VarDecl*> TentativeDefinitions;
-
/// LLVMUsed - List of global values which are required to be
/// present in the object file; bitcast to i8*. This is used for
/// forcing visibility of symbols which may otherwise be optimized
@@ -339,6 +331,8 @@ public:
CXXCtorType Type);
const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type);
+
+ void EmitTentativeDefinition(const VarDecl *D);
enum GVALinkage {
GVA_Internal,
@@ -382,7 +376,6 @@ private:
void EmitGlobalDefinition(const ValueDecl *D);
void EmitGlobalFunctionDefinition(const FunctionDecl *D);
- void EmitTentativeDefinition(const VarDecl *D);
void EmitGlobalVarDefinition(const VarDecl *D);
void EmitAliasDefinition(const ValueDecl *D);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 896464ed5a..9b85df61da 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -83,6 +83,13 @@ namespace {
if (Builder)
Builder->Release();
};
+
+ virtual void CompleteTentativeDefinition(VarDecl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ Builder->EmitTentativeDefinition(D);
+ }
};
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index ed5c431da8..19155b6cc3 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -232,41 +233,39 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
- if (!getLangOptions().CPlusPlus) {
- // Note: we traverse the scope's list of declarations rather than
- // the DeclContext's list, because we only want to see the most
- // recent declaration of each identifier.
- for (Scope::decl_iterator I = TUScope->decl_begin(),
- IEnd = TUScope->decl_end();
- I != IEnd; ++I) {
- Decl *D = (*I).getAs<Decl>();
- if (D->isInvalidDecl())
- continue;
+ for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
+ D = TentativeDefinitions.begin(),
+ DEnd = TentativeDefinitions.end();
+ D != DEnd; ++D) {
+ VarDecl *VD = D->second;
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (VD->isTentativeDefinition(Context)) {
- if (const IncompleteArrayType *ArrayT
- = Context.getAsIncompleteArrayType(VD->getType())) {
- if (RequireCompleteType(VD->getLocation(),
- ArrayT->getElementType(),
- diag::err_tentative_def_incomplete_type_arr))
- VD->setInvalidDecl();
- else {
- // Set the length of the array to 1 (C99 6.9.2p5).
- Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
- llvm::APInt One(Context.getTypeSize(Context.getSizeType()),
- true);
- QualType T
- = Context.getConstantArrayType(ArrayT->getElementType(),
- One, ArrayType::Normal, 0);
- VD->setType(T);
- }
- } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
- diag::err_tentative_def_incomplete_type))
- VD->setInvalidDecl();
- }
+ if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ continue;
+
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(VD->getType())) {
+ if (RequireCompleteType(VD->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_tentative_def_incomplete_type_arr))
+ VD->setInvalidDecl();
+ else {
+ // Set the length of the array to 1 (C99 6.9.2p5).
+ Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
+ llvm::APInt One(Context.getTypeSize(Context.getSizeType()),
+ true);
+ QualType T
+ = Context.getConstantArrayType(ArrayT->getElementType(),
+ One, ArrayType::Normal, 0);
+ VD->setType(T);
}
- }
+ } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
+ diag::err_tentative_def_incomplete_type))
+ VD->setInvalidDecl();
+
+ // Notify the consumer that we've completed a tentative definition.
+ if (!VD->isInvalidDecl())
+ Consumer.CompleteTentativeDefinition(VD);
+
}
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 1f6cd0440c..f3c337c148 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -233,6 +233,14 @@ public:
/// not visible.
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
+ /// \brief The set of tentative declarations seen so far in this
+ /// translation unit for which no definition has been seen.
+ ///
+ /// The tentative declarations are indexed by the name of the
+ /// declaration, and only the most recent tentative declaration for
+ /// a given variable will be recorded here.
+ llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
+
IdentifierResolver IdResolver;
// Enum values used by KnownFunctionIDs (see below).
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 716219c034..abde26ae53 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2545,6 +2545,18 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// Attach the initializer to the decl.
VDecl->setInit(Init);
+
+ // If the previous declaration of VDecl was a tentative definition,
+ // remove it from the set of tentative definitions.
+ if (VDecl->getPreviousDeclaration() &&
+ VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
+ llvm::DenseMap<DeclarationName, VarDecl *>::iterator Pos
+ = TentativeDefinitions.find(VDecl->getDeclName());
+ assert(Pos != TentativeDefinitions.end() &&
+ "Unrecorded tentative definition?");
+ TentativeDefinitions.erase(Pos);
+ }
+
return;
}
@@ -2557,6 +2569,11 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
QualType Type = Var->getType();
+
+ // Record tentative definitions.
+ if (Var->isTentativeDefinition(Context))
+ TentativeDefinitions[Var->getDeclName()] = Var;
+
// C++ [dcl.init.ref]p3:
// The initializer can be omitted for a reference only in a
// parameter declaration (8.3.5), in the declaration of a
diff --git a/test/PCH/external-defs.h b/test/PCH/external-defs.h
index 4d233e2a40..bb51a9d64b 100644
--- a/test/PCH/external-defs.h
+++ b/test/PCH/external-defs.h
@@ -14,5 +14,4 @@ static int z;
int incomplete_array[];
int incomplete_array2[];
-// FIXME: CodeGen problems prevents this from working (<rdar://problem/6762287>)
-// struct S s;
+struct S s;
diff --git a/test/Sema/init.c b/test/Sema/init.c
index cbf75e1bb1..7938ec5568 100644
--- a/test/Sema/init.c
+++ b/test/Sema/init.c
@@ -74,8 +74,7 @@ int sym_fw1a_scr[] = {
};
// PR3001
-struct s1 s2 = { // expected-error{{tentative definition has type 'struct s1' that is never completed}} \
- // expected-note{{forward declaration of 'struct s1'}}
+struct s1 s2 = {
.a = sizeof(struct s3), // expected-error {{invalid application of 'sizeof'}} \
// expected-note{{forward declaration of 'struct s3'}}
.b = bogus // expected-error {{use of undeclared identifier 'bogus'}}
diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c
index 3a830bf428..85b5ed76bd 100644
--- a/test/Sema/tentative-decls.c
+++ b/test/Sema/tentative-decls.c
@@ -57,3 +57,9 @@ void func2(void)
extern double *p;
}
+// <rdar://problem/6808352>
+static int a0[];
+static int b0;
+
+static int a0[] = { 4 };
+static int b0 = 5;
diff --git a/tools/clang-cc/Backend.cpp b/tools/clang-cc/Backend.cpp
index 58ecedb7f2..2d8ca82e2f 100644
--- a/tools/clang-cc/Backend.cpp
+++ b/tools/clang-cc/Backend.cpp
@@ -158,6 +158,10 @@ namespace {
"LLVM IR generation of declaration");
Gen->HandleTagDeclDefinition(D);
}
+
+ virtual void CompleteTentativeDefinition(VarDecl *D) {
+ Gen->CompleteTentativeDefinition(D);
+ }
};
}