diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 45 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 67 |
3 files changed, 59 insertions, 54 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 57ed9884ba7..d8610133f2c 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/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(); + } + } + } + } } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index c4964bf69bd..b3669bc74d2 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -451,7 +451,6 @@ public: bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); bool MergeVarDecl(VarDecl *New, Decl *Old); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); - void CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD); /// C++ Overloading. bool IsOverload(FunctionDecl *New, Decl* OldD, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c5768fd73a3..35573bb33d8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -776,56 +776,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { return false; } -/// Predicate for C "tentative" external object definitions (C99 6.9.2). -static bool isTentativeDefinition(VarDecl *VD) { - if (VD->isFileVarDecl()) - return (!VD->getInit() && - (VD->getStorageClass() == VarDecl::None || - VD->getStorageClass() == VarDecl::Static)); - return false; -} - -/// CheckForFileScopedRedefinitions - Make sure we forgo redefinition errors -/// when dealing with C "tentative" external object definitions (C99 6.9.2). -void Sema::CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD) { - bool VDIsTentative = isTentativeDefinition(VD); - bool VDIsIncompleteArray = VD->getType()->isIncompleteArrayType(); - - // FIXME: I don't think this will actually see all of the - // redefinitions. Can't we check this property on-the-fly? - for (IdentifierResolver::iterator I = IdResolver.begin(VD->getIdentifier()), - E = IdResolver.end(); - I != E; ++I) { - if (*I != VD && isDeclInScope(*I, VD->getDeclContext(), S)) { - VarDecl *OldDecl = dyn_cast<VarDecl>(*I); - - // Handle the following case: - // int a[10]; - // int a[]; - the code below makes sure we set the correct type. - // int a[11]; - this is an error, size isn't 10. - if (OldDecl && VDIsTentative && VDIsIncompleteArray && - OldDecl->getType()->isConstantArrayType()) - VD->setType(OldDecl->getType()); - - // Check for "tentative" definitions. We can't accomplish this in - // MergeVarDecl since the initializer hasn't been attached. - if (!OldDecl || isTentativeDefinition(OldDecl) || VDIsTentative) - continue; - - // Handle __private_extern__ just like extern. - if (OldDecl->getStorageClass() != VarDecl::Extern && - OldDecl->getStorageClass() != VarDecl::PrivateExtern && - VD->getStorageClass() != VarDecl::Extern && - VD->getStorageClass() != VarDecl::PrivateExtern) { - Diag(VD->getLocation(), diag::err_redefinition) << VD->getDeclName(); - Diag(OldDecl->getLocation(), diag::note_previous_definition); - // One redefinition error is enough. - break; - } - } - } -} - /// MergeVarDecl - We just parsed a variable 'New' which has the same name /// and scope as a previous declaration 'Old'. Figure out how to resolve this /// situation, merging decls or emitting diagnostics as appropriate. @@ -876,6 +826,10 @@ bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { Diag(Old->getLocation(), diag::note_previous_definition); return true; } + + // Keep a chain of previous declarations. + New->setPreviousDeclaration(Old); + return false; } @@ -2168,6 +2122,15 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) { return; } + const VarDecl *Def = 0; + if (VDecl->getDefinition(Def)) { + Diag(VDecl->getLocation(), diag::err_redefinition) + << VDecl->getDeclName(); + Diag(Def->getLocation(), diag::note_previous_definition); + VDecl->setInvalidDecl(); + return; + } + // Take ownership of the expression, now that we're sure we have somewhere // to put it. Expr *Init = static_cast<Expr *>(init.release()); @@ -2349,7 +2312,7 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { // storage-class specifier or with the storage-class specifier "static", // constitutes a tentative definition. Note: A tentative definition with // external linkage is valid (C99 6.2.2p5). - if (!getLangOptions().CPlusPlus && isTentativeDefinition(IDecl)) { + if (IDecl->isTentativeDefinition(Context)) { QualType CheckType = T; unsigned DiagID = diag::err_typecheck_decl_incomplete_type; @@ -2369,8 +2332,6 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { IDecl->setInvalidDecl(); } } - if (IDecl->isFileVarDecl()) - CheckForFileScopedRedefinitions(S, IDecl); } return NewGroup; } |