[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