diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 27 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 11 | ||||
-rw-r--r-- | clang/lib/CodeGen/ModuleBuilder.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 65 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 17 |
7 files changed, 79 insertions, 59 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8bda32398fc..0326b34960f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0526e7845cc..9ae93599df1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e7924fade53..21ef8da863c 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/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/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 896464ed5a8..9b85df61da0 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/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/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index ed5c431da82..19155b6cc34 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 1f6cd0440c4..f3c337c148e 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 716219c034a..abde26ae533 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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 |