[cfe-commits] r66601 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Basic/DiagnosticSemaKinds.def lib/AST/Decl.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp test/Sema/enum.c test/Sema/incomplete-decl.c test/Sema/init.c test/Sema/tentative-decls.c
Douglas Gregor
dgregor at apple.com
Tue Mar 10 16:43:53 PDT 2009
Author: dgregor
Date: Tue Mar 10 18:43:53 2009
New Revision: 66601
URL: http://llvm.org/viewvc/llvm-project?rev=66601&view=rev
Log:
Add type checking for tentative definitions at the end of the
translation unit.
Thread the various declarations of variables via
VarDecl::getPreviousDeclaration.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Sema/enum.c
cfe/trunk/test/Sema/incomplete-decl.c
cfe/trunk/test/Sema/init.c
cfe/trunk/test/Sema/tentative-decls.c
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Mar 10 18:43:53 2009
@@ -233,6 +233,9 @@
/// condition, e.g., if (int x = foo()) { ... }.
bool DeclaredInCondition : 1;
+ /// \brief The previous declaration of this variable.
+ VarDecl *PreviousDeclaration;
+
// Move to DeclGroup when it is implemented.
SourceLocation TypeSpecStartLoc;
friend class StmtIteratorBase;
@@ -240,8 +243,9 @@
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
QualType T, StorageClass SC, SourceLocation TSSL = SourceLocation())
: ValueDecl(DK, DC, L, Id, T), Init(0),
- ThreadSpecified(false), HasCXXDirectInit(false),
- DeclaredInCondition(false), TypeSpecStartLoc(TSSL) {
+ ThreadSpecified(false), HasCXXDirectInit(false),
+ DeclaredInCondition(false), PreviousDeclaration(0),
+ TypeSpecStartLoc(TSSL) {
SClass = SC;
}
public:
@@ -261,6 +265,12 @@
Expr *getInit() { return (Expr*) Init; }
void setInit(Expr *I) { Init = (Stmt*) I; }
+ /// \brief Retrieve the definition of this variable, which may come
+ /// from a previous declaration. Def will be set to the VarDecl that
+ /// contains the initializer, and the result will be that
+ /// initializer.
+ const Expr *getDefinition(const VarDecl *&Def);
+
void setThreadSpecified(bool T) { ThreadSpecified = T; }
bool isThreadSpecified() const {
return ThreadSpecified;
@@ -290,6 +300,14 @@
DeclaredInCondition = InCondition;
}
+ /// getPreviousDeclaration - Return the previous declaration of this
+ /// variable.
+ const VarDecl *getPreviousDeclaration() const { return PreviousDeclaration; }
+
+ void setPreviousDeclaration(VarDecl * PrevDecl) {
+ PreviousDeclaration = PrevDecl;
+ }
+
/// hasLocalStorage - Returns true if a variable with function scope
/// is a non-static local variable.
bool hasLocalStorage() const {
@@ -337,6 +355,10 @@
}
return false;
}
+
+ /// \brief Determine whether this is a tentative definition of a
+ /// variable in C.
+ bool isTentativeDefinition(ASTContext &Context) const;
/// \brief Determines whether this variable is a variable with
/// external, C linkage.
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Tue Mar 10 18:43:53 2009
@@ -891,6 +891,11 @@
"arithmetic on pointer to void type")
DIAG(err_typecheck_decl_incomplete_type, ERROR,
"variable has incomplete type %0")
+DIAG(err_tentative_def_incomplete_type, ERROR,
+ "tentative definition has type %0 that is never completed")
+DIAG(err_tentative_def_incomplete_type_arr, ERROR,
+ "tentative definition has array of type %0 that is never completed")
+
DIAG(err_realimag_invalid_type, ERROR,
"invalid type %0 to %1 operator")
DIAG(err_typecheck_sclass_fscope, ERROR,
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Tue Mar 10 18:43:53 2009
@@ -273,6 +273,22 @@
VarDecl::~VarDecl() {
}
+bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
+ if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
+ return false;
+
+ return (!getInit() &&
+ (getStorageClass() == None || getStorageClass() == Static));
+}
+
+const Expr *VarDecl::getDefinition(const VarDecl *&Def) {
+ Def = this;
+ while (Def && !Def->getInit())
+ Def = Def->getPreviousDeclaration();
+
+ return Def? Def->getInit() : 0;
+}
+
//===----------------------------------------------------------------------===//
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Mar 10 18:43:53 2009
@@ -218,7 +218,52 @@
/// 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();
+ }
+ }
+ }
+ }
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Mar 10 18:43:53 2009
@@ -451,7 +451,6 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Mar 10 18:43:53 2009
@@ -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;
}
Modified: cfe/trunk/test/Sema/enum.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/enum.c?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/test/Sema/enum.c (original)
+++ cfe/trunk/test/Sema/enum.c Tue Mar 10 18:43:53 2009
@@ -21,7 +21,9 @@
return sizeof(enum e) ;
}
-enum gccForwardEnumExtension ve; // expected-warning{{ISO C forbids forward references to 'enum' types}}
+enum gccForwardEnumExtension ve; // expected-warning{{ISO C forbids forward references to 'enum' types}} \
+// expected-error{{tentative definition has type 'enum gccForwardEnumExtension' that is never completed}} \
+// expected-note{{forward declaration of 'enum gccForwardEnumExtension'}}
int test2(int i)
{
Modified: cfe/trunk/test/Sema/incomplete-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/incomplete-decl.c?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/test/Sema/incomplete-decl.c (original)
+++ cfe/trunk/test/Sema/incomplete-decl.c Tue Mar 10 18:43:53 2009
@@ -1,9 +1,9 @@
// RUN: clang -fsyntax-only -verify %s
-struct foo; // expected-note 3 {{forward declaration of 'struct foo'}}
+struct foo; // expected-note 4 {{forward declaration of 'struct foo'}}
void b; // expected-error {{variable has incomplete type 'void'}}
-struct foo f; // // FIXME: error because 'struct foo' is never defined
+struct foo f; // expected-error{{tentative definition has type 'struct foo' that is never completed}}
static void c; // expected-error {{variable has incomplete type 'void'}}
static struct foo g; // expected-error {{variable has incomplete type 'struct foo'}}
Modified: cfe/trunk/test/Sema/init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/init.c?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/test/Sema/init.c (original)
+++ cfe/trunk/test/Sema/init.c Tue Mar 10 18:43:53 2009
@@ -74,7 +74,8 @@
};
// PR3001
-struct s1 s2 = {
+struct s1 s2 = { // expected-error{{tentative definition has type 'struct s1' that is never completed}} \
+ // expected-note{{forward declaration of 'struct s1'}}
.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'}}
Modified: cfe/trunk/test/Sema/tentative-decls.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/tentative-decls.c?rev=66601&r1=66600&r2=66601&view=diff
==============================================================================
--- cfe/trunk/test/Sema/tentative-decls.c (original)
+++ cfe/trunk/test/Sema/tentative-decls.c Tue Mar 10 18:43:53 2009
@@ -5,7 +5,10 @@
static struct a x2; // expected-error{{variable has incomplete type 'struct a'}}
struct a x3[10]; // expected-error{{array has incomplete element type 'struct a'}}
struct a {int x;};
-struct b x4; // FIXME: error because 'struct b' is never defined
+static struct a x2_okay;
+struct a x3_okay[10];
+struct b x4; // expected-error{{tentative definition has type 'struct b' that is never completed}} \
+ // expected-note{{forward declaration of 'struct b'}}
const int a [1] = {1};
extern const int a[];
@@ -23,8 +26,8 @@
extern int i1; // expected-note {{previous definition is here}}
static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}}
-static int i2 = 5; // expected-note 2 {{previous definition is here}}
-int i2 = 3; // expected-error{{redefinition of 'i2'}} expected-error{{non-static declaration of 'i2' follows static declaration}}
+static int i2 = 5; // expected-note 1 {{previous definition is here}}
+int i2 = 3; // expected-error{{non-static declaration of 'i2' follows static declaration}}
__private_extern__ int pExtern;
int pExtern = 0;
More information about the cfe-commits
mailing list