[cfe-commits] r39241 - in /cfe/cfe/trunk: AST/SemaDecl.cpp Parse/ParseDecl.cpp Parse/Parser.cpp Sema/SemaDecl.cpp include/clang/Basic/DiagnosticKinds.def include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h

sabre at cs.uiuc.edu sabre at cs.uiuc.edu
Wed Jul 11 09:41:46 PDT 2007


Author: sabre
Date: Wed Jul 11 11:41:46 2007
New Revision: 39241

URL: http://llvm.org/viewvc/llvm-project?rev=39241&view=rev
Log:
Scrutinize K&R parameter declarations.  This implements C99 6.9.1p6, correctly
diagnosing malformed K&R function definitions.

Modified:
    cfe/cfe/trunk/AST/SemaDecl.cpp
    cfe/cfe/trunk/Parse/ParseDecl.cpp
    cfe/cfe/trunk/Parse/Parser.cpp
    cfe/cfe/trunk/Sema/SemaDecl.cpp
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/cfe/trunk/include/clang/Parse/Parser.h

Modified: cfe/cfe/trunk/AST/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaDecl.cpp?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/AST/SemaDecl.cpp Wed Jul 11 11:41:46 2007
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Type.h"
 #include "clang/Parse/DeclSpec.h"
@@ -105,6 +106,28 @@
 Sema::DeclTy *Sema::ParseStartOfFunctionDef(Scope *S, Declarator &D
                                             /* TODO: FORMAL ARG INFO.*/) {
   assert(CurFunctionDecl == 0 && "Function parsing confused");
+  assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+         "Not a function declarator!");
+  DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+  
+  // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
+  // for a K&R function.
+  if (!FTI.hasPrototype) {
+    for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+      if (FTI.ArgInfo[i].TypeInfo == 0) {
+        Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_not_declared,
+             FTI.ArgInfo[i].Ident->getName());
+        // Implicitly declare the argument as type 'int' for lack of a better
+        // type.
+        FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr();
+      }
+    }
+   
+    // Since this is a function definition, act as though we have information
+    // about the arguments.
+    FTI.hasPrototype = true;
+  }
+  
   
   FunctionDecl *FD = static_cast<FunctionDecl*>(ParseDeclarator(S, D, 0, 0));
   CurFunctionDecl = FD;

Modified: cfe/cfe/trunk/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseDecl.cpp?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/Parse/ParseDecl.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseDecl.cpp Wed Jul 11 11:41:46 2007
@@ -967,8 +967,9 @@
         }
           
       // Remember this identifier in ParamInfo.
-      ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, Tok.getLocation(),
-                                                     0));
+      if (ParmII)
+        ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+                                                       Tok.getLocation(), 0));
       
       // Eat the identifier.
       ConsumeToken();
@@ -1017,17 +1018,12 @@
         ParseAttributes();
       
       // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
-      switch (DS.getStorageClassSpec()) {
-      case DeclSpec::SCS_unspecified:
-      case DeclSpec::SCS_register:
-        break;
-      case DeclSpec::SCS_auto:
-        // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted.
-      default:
+      // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted.
+      if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+          DS.getStorageClassSpec() != DeclSpec::SCS_register) {
         Diag(DS.getStorageClassSpecLoc(),
              diag::err_invalid_storage_class_in_func_decl);
         DS.ClearStorageClassSpecs();
-        break;
       }
       if (DS.isThreadSpecified()) {
         Diag(DS.getThreadSpecLoc(),

Modified: cfe/cfe/trunk/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/Parser.cpp?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/Parse/Parser.cpp (original)
+++ cfe/cfe/trunk/Parse/Parser.cpp Wed Jul 11 11:41:46 2007
@@ -402,30 +402,22 @@
   const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
   assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
          "This isn't a function declarator!");
-
-  DeclTy *Res = Actions.ParseStartOfFunctionDef(CurScope, D);
-  
-  // FIXME: Enter a scope for the arguments.
-  //EnterScope(Scope::FnScope);
-  
-  
+  const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun;
   
   // If this declaration was formed with a K&R-style identifier list for the
   // arguments, parse declarations for all of the args next.
   // int foo(a,b) int a; float b; {}
-  if (!FnTypeInfo.Fun.hasPrototype && FnTypeInfo.Fun.NumArgs != 0) {
-    // Read all the argument declarations.
-    while (isDeclarationSpecifier())
-      ParseDeclaration(Declarator::KNRTypeListContext);
-    
-    // Note, check that we got them all.
-  } else {
-    //if (isDeclarationSpecifier())
-    //  Diag('k&r declspecs with prototype?');
-    
-    // TODO: Install the arguments into the current scope.
-  }
+  if (!FTI.hasPrototype && FTI.NumArgs != 0)
+    ParseKNRParamDeclarations(D);
 
+  // Enter a scope for the function body.
+  EnterScope(Scope::FnScope);
+  
+  
+  
+  DeclTy *Res = Actions.ParseStartOfFunctionDef(CurScope, D);
+  
+  
   // We should have an opening brace now.
   if (Tok.getKind() != tok::l_brace) {
     Diag(Tok, diag::err_expected_fn_body);
@@ -434,21 +426,136 @@
     SkipUntil(tok::l_brace, true, true);
     
     // If we didn't find the '{', bail out.
-    if (Tok.getKind() != tok::l_brace)
+    if (Tok.getKind() != tok::l_brace) {
+      ExitScope();
       return 0;
+    }
   }
   
   // Parse the function body as a compound stmt.
   StmtResult FnBody = ParseCompoundStatement();
-  if (FnBody.isInvalid) return 0;
+  if (FnBody.isInvalid) {
+    ExitScope();
+    return 0;
+  }
 
-  // FIXME: Leave the argument scope.
-  // ExitScope();
+  // Leave the function body scope.
+  ExitScope();
 
   // TODO: Pass argument information.
   return Actions.ParseFunctionDefBody(Res, FnBody.Val);
 }
 
+/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
+/// types for a function with a K&R-style identifier list for arguments.
+void Parser::ParseKNRParamDeclarations(Declarator &D) {
+  // We know that the top-level of this declarator is a function.
+  DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+  // Read all the argument declarations.
+  while (isDeclarationSpecifier()) {
+    SourceLocation DSStart = Tok.getLocation();
+    
+    // Parse the common declaration-specifiers piece.
+    DeclSpec DS;
+    ParseDeclarationSpecifiers(DS);
+    
+    // C99 6.9.1p6: 'each declaration in the declaration list shall have at
+    // least one declarator'.
+    // NOTE: GCC just makes this an ext-warn.  It's not clear what it does with
+    // the declarations though.  It's trivial to ignore them, really hard to do
+    // anything else with them.
+    if (Tok.getKind() == tok::semi) {
+      Diag(DSStart, diag::err_declaration_does_not_declare_param);
+      ConsumeToken();
+      continue;
+    }
+    
+    // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other
+    // than register.
+    if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+        DS.getStorageClassSpec() != DeclSpec::SCS_register) {
+      Diag(DS.getStorageClassSpecLoc(),
+           diag::err_invalid_storage_class_in_func_decl);
+      DS.ClearStorageClassSpecs();
+    }
+    if (DS.isThreadSpecified()) {
+      Diag(DS.getThreadSpecLoc(),
+           diag::err_invalid_storage_class_in_func_decl);
+      DS.ClearStorageClassSpecs();
+    }
+    
+    // Parse the first declarator attached to this declspec.
+    Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext);
+    ParseDeclarator(ParmDeclarator);
+
+    // Handle the full declarator list.
+    while (1) {
+      // If attributes are present, parse them.
+      if (Tok.getKind() == tok::kw___attribute)
+        // FIXME: attach attributes too.
+        ParseAttributes();
+      
+      // Ask the actions module to compute the type for this declarator.
+      Action::TypeResult TR =
+        Actions.ParseParamDeclaratorType(CurScope, ParmDeclarator);
+      if (!TR.isInvalid && 
+          // A missing identifier has already been diagnosed.
+          ParmDeclarator.getIdentifier()) {
+
+        // Scan the argument list looking for the correct param to apply this
+        // type.
+        for (unsigned i = 0; ; ++i) {
+          // C99 6.9.1p6: those declarators shall declare only identifiers from
+          // the identifier list.
+          if (i == FTI.NumArgs) {
+            Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param,
+                 ParmDeclarator.getIdentifier()->getName());
+            break;
+          }
+          
+          if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
+            // Reject redefinitions of parameters.
+            if (FTI.ArgInfo[i].TypeInfo) {
+              Diag(ParmDeclarator.getIdentifierLoc(),
+                   diag::err_param_redefinition,
+                   ParmDeclarator.getIdentifier()->getName());
+            } else {
+              FTI.ArgInfo[i].TypeInfo = TR.Val;
+            }
+            break;
+          }
+        }
+      }
+
+      // 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.
+      ParmDeclarator.clear();
+      ParseDeclarator(ParmDeclarator);
+    }
+    
+    if (Tok.getKind() == tok::semi) {
+      ConsumeToken();
+    } else {
+      Diag(Tok, diag::err_parse_error);
+      // Skip to end of block or statement
+      SkipUntil(tok::semi, true);
+      if (Tok.getKind() == tok::semi)
+        ConsumeToken();
+    }
+  }
+  
+  // The actions module must verify that all arguments were declared.
+}
+
+
 /// ParseAsmStringLiteral - This is just a normal string-literal, but is not
 /// allowed to be a wide string, and is not subject to character translation.
 ///

Modified: cfe/cfe/trunk/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaDecl.cpp?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaDecl.cpp Wed Jul 11 11:41:46 2007
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Type.h"
 #include "clang/Parse/DeclSpec.h"
@@ -105,6 +106,28 @@
 Sema::DeclTy *Sema::ParseStartOfFunctionDef(Scope *S, Declarator &D
                                             /* TODO: FORMAL ARG INFO.*/) {
   assert(CurFunctionDecl == 0 && "Function parsing confused");
+  assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+         "Not a function declarator!");
+  DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+  
+  // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
+  // for a K&R function.
+  if (!FTI.hasPrototype) {
+    for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+      if (FTI.ArgInfo[i].TypeInfo == 0) {
+        Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_not_declared,
+             FTI.ArgInfo[i].Ident->getName());
+        // Implicitly declare the argument as type 'int' for lack of a better
+        // type.
+        FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr();
+      }
+    }
+   
+    // Since this is a function definition, act as though we have information
+    // about the arguments.
+    FTI.hasPrototype = true;
+  }
+  
   
   FunctionDecl *FD = static_cast<FunctionDecl*>(ParseDeclarator(S, D, 0, 0));
   CurFunctionDecl = FD;

Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:41:46 2007
@@ -402,6 +402,14 @@
      "'void' as parameter must not have type qualifiers")
 DIAG(err_param_redefinition, ERROR,
      "redefinition of parameter '%s'")
+DIAG(err_ident_list_in_fn_declaration, ERROR,
+     "a parameter list without types is only allowed in a function definition")
+DIAG(err_declaration_does_not_declare_param, ERROR,
+     "declaration does not declare a parameter")
+DIAG(err_no_matching_param, ERROR,
+     "parameter named '%s' is missing")
+DIAG(err_param_not_declared, ERROR,
+     "parameter '%s' was not declared")
 
 DIAG(err_unexpected_typedef, ERROR,
      "unexpected type name '%s': expected expression")

Modified: cfe/cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/DeclSpec.h Wed Jul 11 11:41:46 2007
@@ -261,7 +261,7 @@
     IdentifierInfo *Ident;
     SourceLocation IdentLoc;
     Action::TypeTy *TypeInfo;
-    
+    // FIXME: this also needs an attribute list.
     ParamInfo() {}
     ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::TypeTy *typ)
       : Ident(ident), IdentLoc(iloc), TypeInfo(typ) {
@@ -441,6 +441,11 @@
   /// Return the specified TypeInfo from this declarator.  TypeInfo #0 is
   /// closest to the identifier.
   const DeclaratorChunk &getTypeObject(unsigned i) const {
+    assert(i < DeclTypeInfo.size() && "Invalid type chunk");
+    return DeclTypeInfo[i];
+  }
+  DeclaratorChunk &getTypeObject(unsigned i) {
+    assert(i < DeclTypeInfo.size() && "Invalid type chunk");
     return DeclTypeInfo[i];
   }
   

Modified: cfe/cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Parser.h?rev=39241&r1=39240&r2=39241&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Parser.h Wed Jul 11 11:41:46 2007
@@ -236,6 +236,7 @@
   DeclTy *ParseExternalDeclaration();
   DeclTy *ParseDeclarationOrFunctionDefinition();
   DeclTy *ParseFunctionDefinition(Declarator &D);
+  void ParseKNRParamDeclarations(Declarator &D);
   void ParseSimpleAsm();
   void ParseAsmStringLiteral();
 





More information about the cfe-commits mailing list