[cfe-commits] r39286 - in /cfe/cfe/trunk: AST/Sema.h AST/SemaDecl.cpp Parse/ParseDecl.cpp Sema/Sema.h Sema/SemaDecl.cpp clang.xcodeproj/project.pbxproj include/clang/AST/Decl.h include/clang/Parse/Action.h
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:42:30 PDT 2007
Author: sabre
Date: Wed Jul 11 11:42:29 2007
New Revision: 39286
URL: http://llvm.org/viewvc/llvm-project?rev=39286&view=rev
Log:
simplify structure body parsing code. Reorganize how tags are processed.
Diagnose redefintion of tag types, e.g.:
t.c:7:8: error: redefinition of 'blah'
struct blah {};
^
t.c:1:8: error: previous definition is here
struct blah {
^
2 diagnostics generated.
Modified:
cfe/cfe/trunk/AST/Sema.h
cfe/cfe/trunk/AST/SemaDecl.cpp
cfe/cfe/trunk/Parse/ParseDecl.cpp
cfe/cfe/trunk/Sema/Sema.h
cfe/cfe/trunk/Sema/SemaDecl.cpp
cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
cfe/cfe/trunk/include/clang/AST/Decl.h
cfe/cfe/trunk/include/clang/Parse/Action.h
Modified: cfe/cfe/trunk/AST/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.h?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:42:29 2007
@@ -83,7 +83,7 @@
Decl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S);
- virtual DeclTy *ParseTag(Scope *S, unsigned TagType, bool isUse,
+ virtual DeclTy *ParseTag(Scope *S, unsigned TagType, TagKind TK,
SourceLocation KWLoc, IdentifierInfo *Name,
SourceLocation NameLoc);
Modified: cfe/cfe/trunk/AST/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaDecl.cpp?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/AST/SemaDecl.cpp Wed Jul 11 11:42:29 2007
@@ -265,14 +265,14 @@
/// ParseStructUnionTag - This is invoked when we see 'struct foo' or
/// 'struct {'. In the former case, Name will be non-null. In the later case,
-/// Name will be null. TagType indicates what kind of tag this is. isUse
-/// indicates whether this is a use of a preexisting struct tag, or if it is a
-/// definition or declaration of a new one.
-Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, bool isUse,
+/// Name will be null. TagType indicates what kind of tag this is. TK indicates
+/// whether this is a reference/declaration/definition of a tag.
+Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
SourceLocation KWLoc, IdentifierInfo *Name,
SourceLocation NameLoc) {
// If this is a use of an existing tag, it must have a name.
- assert((!isUse || Name != 0) && "Nameless record must be a definition!");
+ assert((Name != 0 || TK == TK_Definition) &&
+ "Nameless record must be a definition!");
Decl::Kind Kind;
switch (TagType) {
@@ -285,21 +285,39 @@
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
- if (Decl *PrevDecl = LookupScopedDecl(Name, Decl::IDNS_Tag)) {
+ if (TagDecl *PrevDecl =
+ dyn_cast_or_null<TagDecl>(LookupScopedDecl(Name, Decl::IDNS_Tag))) {
// If this is a use of a previous tag, or if the tag is already declared in
// the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
- if (isUse || S->isDeclScope(PrevDecl)) {
+ if (TK == TK_Reference || S->isDeclScope(PrevDecl)) {
// Make sure that this wasn't declared as an enum and now used as a struct
// or something similar.
if (PrevDecl->getKind() != Kind) {
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
Diag(PrevDecl->getLocation(), diag::err_previous_use);
}
+
+ // If this is a use or a forward declaration, we're good.
+ if (TK != TK_Definition)
+ return PrevDecl;
- // Okay, this is a reference to the old decl, return it.
- return PrevDecl;
+ // Diagnose attempts to redefine a tag.
+ if (PrevDecl->isDefinition()) {
+ Diag(NameLoc, diag::err_redefinition, Name->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ // If this is a redefinition, recover by making this struct be
+ // anonymous, which will make any later references get the previous
+ // definition.
+ Name = 0;
+ } else {
+ // Okay, this is definition of a previously declared or referenced tag.
+ // Move the location of the decl to be the definition site.
+ PrevDecl->setLocation(NameLoc);
+ PrevDecl->setDefinition(true);
+ return PrevDecl;
+ }
}
// If we get here, this is a definition of a new struct type in a nested
// scope, e.g. "struct foo; void bar() { struct foo; }", just create a new
@@ -312,12 +330,15 @@
SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
// Otherwise, if this is the first time we've seen this tag, create the decl.
- Decl *New;
+ TagDecl *New;
if (Kind != Decl::Enum)
New = new RecordDecl(Kind, Loc, Name);
else
assert(0 && "Enum tags not implemented yet!");
+ if (TK == TK_Definition)
+ New->setDefinition(true);
+
// If this has an identifier, add it to the scope stack.
if (Name) {
New->setNext(Name->getFETokenInfo<Decl>());
Modified: cfe/cfe/trunk/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseDecl.cpp?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/ParseDecl.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseDecl.cpp Wed Jul 11 11:42:29 2007
@@ -435,17 +435,21 @@
// There are three options here. If we have 'struct foo;', then this is a
// forward declaration. If we have 'struct foo {...' then this is a
- // definition. Otherwise we have something like 'struct foo xyz', a use. Tell
- // the actions module whether this is a definition (forward or not) of the
- // type insted of a use.
+ // definition. Otherwise we have something like 'struct foo xyz', a reference.
//
// This is needed to handle stuff like this right (C99 6.7.2.3p11):
// struct foo {..}; void bar() { struct foo; } <- new foo in bar.
// struct foo {..}; void bar() { struct foo x; } <- use of old foo.
//
- bool isUse = Tok.getKind() != tok::l_brace && Tok.getKind() != tok::semi;
+ Action::TagKind TK;
+ if (Tok.getKind() == tok::l_brace)
+ TK = Action::TK_Definition;
+ else if (Tok.getKind() == tok::semi)
+ TK = Action::TK_Declaration;
+ else
+ TK = Action::TK_Reference;
DeclTy *TagDecl =
- Actions.ParseTag(CurScope, TagType, isUse, StartLoc, Name, NameLoc);
+ Actions.ParseTag(CurScope, TagType, TK, StartLoc, Name, NameLoc);
// If there is a body, parse it and inform the actions module.
if (Tok.getKind() == tok::l_brace)
@@ -483,10 +487,16 @@
void Parser::ParseStructUnionBody(unsigned TagType, DeclTy *TagDecl) {
SourceLocation LBraceLoc = ConsumeBrace();
+ // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
+ // C++.
if (Tok.getKind() == tok::r_brace)
Diag(Tok, diag::ext_empty_struct_union_enum,
DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
+
+ // Enter a scope to capture the struct declarations.
+ EnterScope(0);
+ // While we still have something to read, read the declarations in the struct.
while (Tok.getKind() != tok::r_brace &&
Tok.getKind() != tok::eof) {
// Each iteration of this loop reads one struct-declaration.
@@ -498,50 +508,58 @@
// TODO: Does specifier-qualifier list correctly check that *something* is
// specified?
- Declarator DeclaratorInfo(DS, Declarator::MemberContext);
-
// If there are no declarators, issue a warning.
if (Tok.getKind() == tok::semi) {
Diag(SpecQualLoc, diag::w_no_declarators);
- } else {
- // Read struct-declarators until we find the semicolon.
- while (1) {
- /// struct-declarator: declarator
- /// struct-declarator: declarator[opt] ':' constant-expression
- if (Tok.getKind() != tok::colon)
- ParseDeclarator(DeclaratorInfo);
-
- if (Tok.getKind() == tok::colon) {
- ConsumeToken();
- ExprResult Res = ParseConstantExpression();
- if (Res.isInvalid) {
- SkipUntil(tok::semi, true, true);
- } else {
- // Process it.
- }
- }
-
- // If attributes exist after the declarator, parse them.
- if (Tok.getKind() == tok::kw___attribute)
- ParseAttributes();
-
- // TODO: install declarator.
-
- // If we don't have a comma, it is either the end of the list (a ';')
- // or an error, bail out.
- if (Tok.getKind() != tok::comma)
- break;
-
- // Consume the comma.
+ ConsumeToken();
+ continue;
+ }
+
+ // Read struct-declarators until we find the semicolon.
+ Declarator DeclaratorInfo(DS, Declarator::MemberContext);
+
+ while (1) {
+ /// struct-declarator: declarator
+ /// struct-declarator: declarator[opt] ':' constant-expression
+ if (Tok.getKind() != tok::colon)
+ ParseDeclarator(DeclaratorInfo);
+
+ ExprTy *BitfieldSize = 0;
+ if (Tok.getKind() == tok::colon) {
ConsumeToken();
-
- // Parse the next declarator.
- DeclaratorInfo.clear();
-
- // Attributes are only allowed on the second declarator.
- if (Tok.getKind() == tok::kw___attribute)
- ParseAttributes();
+ ExprResult Res = ParseConstantExpression();
+ if (Res.isInvalid) {
+ SkipUntil(tok::semi, true, true);
+ } else {
+ BitfieldSize = Res.Val;
+ }
}
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ ParseAttributes();
+
+ // TODO: install declarator.
+
+
+ //LastDeclInGroup = Actions.ParseDeclarator(CurScope, D, Init.Val,
+ //LastDeclInGroup);
+
+
+ // If we don't have a comma, it is either the end of the list (a ';')
+ // or an error, bail out.
+ if (Tok.getKind() != tok::comma)
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ DeclaratorInfo.clear();
+
+ // Attributes are only allowed on the second declarator.
+ if (Tok.getKind() == tok::kw___attribute)
+ ParseAttributes();
}
if (Tok.getKind() == tok::semi) {
@@ -553,6 +571,8 @@
}
}
+ ExitScope();
+
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
// If attributes exist after struct contents, parse them.
Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:42:29 2007
@@ -83,7 +83,7 @@
Decl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S);
- virtual DeclTy *ParseTag(Scope *S, unsigned TagType, bool isUse,
+ virtual DeclTy *ParseTag(Scope *S, unsigned TagType, TagKind TK,
SourceLocation KWLoc, IdentifierInfo *Name,
SourceLocation NameLoc);
Modified: cfe/cfe/trunk/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaDecl.cpp?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaDecl.cpp Wed Jul 11 11:42:29 2007
@@ -265,14 +265,14 @@
/// ParseStructUnionTag - This is invoked when we see 'struct foo' or
/// 'struct {'. In the former case, Name will be non-null. In the later case,
-/// Name will be null. TagType indicates what kind of tag this is. isUse
-/// indicates whether this is a use of a preexisting struct tag, or if it is a
-/// definition or declaration of a new one.
-Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, bool isUse,
+/// Name will be null. TagType indicates what kind of tag this is. TK indicates
+/// whether this is a reference/declaration/definition of a tag.
+Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
SourceLocation KWLoc, IdentifierInfo *Name,
SourceLocation NameLoc) {
// If this is a use of an existing tag, it must have a name.
- assert((!isUse || Name != 0) && "Nameless record must be a definition!");
+ assert((Name != 0 || TK == TK_Definition) &&
+ "Nameless record must be a definition!");
Decl::Kind Kind;
switch (TagType) {
@@ -285,21 +285,39 @@
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
- if (Decl *PrevDecl = LookupScopedDecl(Name, Decl::IDNS_Tag)) {
+ if (TagDecl *PrevDecl =
+ dyn_cast_or_null<TagDecl>(LookupScopedDecl(Name, Decl::IDNS_Tag))) {
// If this is a use of a previous tag, or if the tag is already declared in
// the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
- if (isUse || S->isDeclScope(PrevDecl)) {
+ if (TK == TK_Reference || S->isDeclScope(PrevDecl)) {
// Make sure that this wasn't declared as an enum and now used as a struct
// or something similar.
if (PrevDecl->getKind() != Kind) {
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
Diag(PrevDecl->getLocation(), diag::err_previous_use);
}
+
+ // If this is a use or a forward declaration, we're good.
+ if (TK != TK_Definition)
+ return PrevDecl;
- // Okay, this is a reference to the old decl, return it.
- return PrevDecl;
+ // Diagnose attempts to redefine a tag.
+ if (PrevDecl->isDefinition()) {
+ Diag(NameLoc, diag::err_redefinition, Name->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ // If this is a redefinition, recover by making this struct be
+ // anonymous, which will make any later references get the previous
+ // definition.
+ Name = 0;
+ } else {
+ // Okay, this is definition of a previously declared or referenced tag.
+ // Move the location of the decl to be the definition site.
+ PrevDecl->setLocation(NameLoc);
+ PrevDecl->setDefinition(true);
+ return PrevDecl;
+ }
}
// If we get here, this is a definition of a new struct type in a nested
// scope, e.g. "struct foo; void bar() { struct foo; }", just create a new
@@ -312,12 +330,15 @@
SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
// Otherwise, if this is the first time we've seen this tag, create the decl.
- Decl *New;
+ TagDecl *New;
if (Kind != Decl::Enum)
New = new RecordDecl(Kind, Loc, Name);
else
assert(0 && "Enum tags not implemented yet!");
+ if (TK == TK_Definition)
+ New->setDefinition(true);
+
// If this has an identifier, add it to the scope stack.
if (Name) {
New->setNext(Name->getFETokenInfo<Decl>());
Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:42:29 2007
@@ -140,7 +140,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; };
DE06BECA0A854E4B0050E87E /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Parse/Scope.h; sourceTree = "<group>"; };
Modified: cfe/cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Decl.h?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Decl.h Wed Jul 11 11:42:29 2007
@@ -65,6 +65,7 @@
IdentifierInfo *getIdentifier() const { return Identifier; }
SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
const char *getName() const;
Kind getKind() const { return DeclKind; }
@@ -186,10 +187,21 @@
/// TagDecl - Represents the declaration of a struct/union/class/enum.
class TagDecl : public Decl {
+ /// IsDefinition - True if this is a definition ("struct foo {};"), false if
+ /// it is a declaration ("struct foo;").
+ bool IsDefinition;
protected:
- TagDecl(Kind DK, SourceLocation L, IdentifierInfo *Id) : Decl(DK, L, Id) {}
+ TagDecl(Kind DK, SourceLocation L, IdentifierInfo *Id) : Decl(DK, L, Id) {
+ IsDefinition = false;
+ }
public:
+ /// isDefinition - Return true if this decl has its body specified.
+ bool isDefinition() const {
+ return IsDefinition;
+ }
+ void setDefinition(bool V) { IsDefinition = V; }
+
const char *getKindName() const {
switch (getKind()) {
default: assert(0 && "Unknown TagDecl!");
Modified: cfe/cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Action.h?rev=39286&r1=39285&r2=39286&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Action.h Wed Jul 11 11:42:29 2007
@@ -140,7 +140,12 @@
return 0;
}
- virtual DeclTy *ParseTag(Scope *S, unsigned TagType, bool isUse,
+ enum TagKind {
+ TK_Reference, // Reference to a tag: 'struct foo *X;'
+ TK_Declaration, // Fwd decl of a tag: 'struct foo;'
+ TK_Definition // Definition of a tag: 'struct foo { int X; } Y;'
+ };
+ virtual DeclTy *ParseTag(Scope *S, unsigned TagType, TagKind TK,
SourceLocation KWLoc, IdentifierInfo *Name,
SourceLocation NameLoc) {
// TagType is an instance of DeclSpec::TST, indicating what kind of tag this
More information about the cfe-commits
mailing list