[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