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
/// 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() {
}
if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
return false;
- return (!getInit() &&
+ const VarDecl *Def = 0;
+ return (!getDefinition(Def) &&
(getStorageClass() == None || getStorageClass() == Static));
}
// 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
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Invalid decl");
+
return VD->getStorageClass() == VarDecl::Static;
}
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
// 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;
/// 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
CXXCtorType Type);
const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type);
+
+ void EmitTentativeDefinition(const VarDecl *D);
enum GVALinkage {
GVA_Internal,
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);
if (Builder)
Builder->Release();
};
+
+ virtual void CompleteTentativeDefinition(VarDecl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ Builder->EmitTentativeDefinition(D);
+ }
};
}
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
// 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);
+
}
}
/// 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).
// 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;
}
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
int incomplete_array[];
int incomplete_array2[];
-// FIXME: CodeGen problems prevents this from working (<rdar://problem/6762287>)
-// struct S s;
+struct S s;
};
// 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'}}
extern double *p;
}
+// <rdar://problem/6808352>
+static int a0[];
+static int b0;
+
+static int a0[] = { 4 };
+static int b0 = 5;
"LLVM IR generation of declaration");
Gen->HandleTagDeclDefinition(D);
}
+
+ virtual void CompleteTentativeDefinition(VarDecl *D) {
+ Gen->CompleteTentativeDefinition(D);
+ }
};
}