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
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c5768fd..35573bb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -776,56 +776,6 @@
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 @@
Diag(Old->getLocation(), diag::note_previous_definition);
return true;
}
+
+ // Keep a chain of previous declarations.
+ New->setPreviousDeclaration(Old);
+
return false;
}
@@ -2168,6 +2122,15 @@
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 @@
// 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 @@
IDecl->setInvalidDecl();
}
}
- if (IDecl->isFileVarDecl())
- CheckForFileScopedRedefinitions(S, IDecl);
}
return NewGroup;
}