aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/Sema.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-10 23:43:53 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-10 23:43:53 +0000
commit275a369f003f25bd22c00c1c0fc0251c7208caf4 (patch)
treef9088a9b40a3ce195904954931a36c1adb532f15 /lib/Sema/Sema.cpp
parentdd98e2cad165ca73c769e4f105a4e47c2216387a (diff)
Add type checking for tentative definitions at the end of the
translation unit. Thread the various declarations of variables via VarDecl::getPreviousDeclaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66601 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r--lib/Sema/Sema.cpp45
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 57ed9884ba..d8610133f2 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -218,7 +218,52 @@ void Sema::DeleteStmt(StmtTy *S) {
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
+ // C99 6.9.2p2:
+ // A declaration of an identifier for an object that has file
+ // scope without an initializer, and without a storage-class
+ // specifier or with the storage-class specifier static,
+ // constitutes a tentative definition. If a translation unit
+ // contains one or more tentative definitions for an identifier,
+ // and the translation unit contains no external definition for
+ // that identifier, then the behavior is exactly as if the
+ // 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 = static_cast<Decl *>(*I);
+ if (D->isInvalidDecl())
+ continue;
+ 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).
+ llvm::APSInt 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();
+ }
+ }
+ }
+ }
}