From 371ed4e7a9301b22ccb19064cede0947384826e8 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 6 Apr 2008 06:57:35 +0000 Subject: [PATCH] now that identifier list parsing is split out, simplify handling of normal typed argument lists. llvm-svn: 49272 --- clang/lib/Parse/ParseDecl.cpp | 217 ++++++++++++++++------------------ 1 file changed, 104 insertions(+), 113 deletions(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0cf97d22de77..3ea0d9f4c17b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -447,7 +447,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec); break; case tok::kw___private_extern__: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, PrevSpec); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, + PrevSpec); break; case tok::kw_static: if (DS.isThreadSpecified()) @@ -1241,18 +1242,16 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { // Okay, this is the parameter list of a function definition, or it is an // identifier list of a K&R-style function. - bool IsVariadic; - bool HasPrototype; - bool ErrorEmitted = false; - - // Build up an array of information about the parsed arguments. - llvm::SmallVector ParamInfo; - llvm::SmallSet ParamsSoFar; if (Tok.is(tok::r_paren)) { + // Remember that we parsed a function type, and remember the attributes. // int() -> no prototype, no '...'. - IsVariadic = false; - HasPrototype = false; + D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/ false, + /*variadic*/ false, + /*arglist*/ 0, 0, LParenLoc)); + + ConsumeParen(); // Eat the closing ')'. + return; } else if (Tok.is(tok::identifier) && // K&R identifier lists can't have typedefs as identifiers, per // C99 6.7.5.3p11. @@ -1260,120 +1259,112 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { // Identifier list. Note that '(' identifier-list ')' is only allowed for // normal declarators, not for abstract-declarators. return ParseFunctionDeclaratorIdentifierList(LParenLoc, D); - } else { - // Finally, a normal, non-empty parameter type list. - - // Enter function-declaration scope, limiting any declarators for struct - // tags to the function prototype scope. - // FIXME: is this needed? - EnterScope(Scope::DeclScope); - - IsVariadic = false; - while (1) { - if (Tok.is(tok::ellipsis)) { - IsVariadic = true; - - // Check to see if this is "void(...)" which is not allowed. - if (ParamInfo.empty()) { - // Otherwise, parse parameter type list. If it starts with an - // ellipsis, diagnose the malformed function. - Diag(Tok, diag::err_ellipsis_first_arg); - IsVariadic = false; // Treat this like 'void()'. - } - - // Consume the ellipsis. - ConsumeToken(); - break; - } + } + + // Finally, a normal, non-empty parameter type list. + + // Build up an array of information about the parsed arguments. + llvm::SmallVector ParamInfo; + llvm::SmallSet ParamsSoFar; + + // Enter function-declaration scope, limiting any declarators for struct + // tags to the function prototype scope. + // FIXME: is this needed? + EnterScope(Scope::DeclScope); + + bool IsVariadic = false; + while (1) { + if (Tok.is(tok::ellipsis)) { + IsVariadic = true; - SourceLocation DSStart = Tok.getLocation(); - - // Parse the declaration-specifiers. - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - - // Parse the declarator. This is "PrototypeContext", because we must - // accept either 'declarator' or 'abstract-declarator' here. - Declarator ParmDecl(DS, Declarator::PrototypeContext); - ParseDeclarator(ParmDecl); - - // Parse GNU attributes, if present. - if (Tok.is(tok::kw___attribute)) - ParmDecl.AddAttributes(ParseAttributes()); - - // Verify C99 6.7.5.3p2: The only SCS allowed is '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(); - } - - // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDecl.getIdentifier(); - - // Verify that the argument identifier has not already been mentioned. - if (ParmII && !ParamsSoFar.insert(ParmII)) { - Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition, - ParmII->getName()); - ParmII = 0; - ParmDecl.setInvalidType(true); + // Check to see if this is "void(...)" which is not allowed. + if (ParamInfo.empty()) { + // Otherwise, parse parameter type list. If it starts with an + // ellipsis, diagnose the malformed function. + Diag(Tok, diag::err_ellipsis_first_arg); + IsVariadic = false; // Treat this like 'void()'. } - // If no parameter was specified, verify that *something* was specified, - // otherwise we have a missing type and identifier. - if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && - ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) { - // Completely missing, emit error. - Diag(DSStart, diag::err_missing_param); - } else { - // Otherwise, we have something. Add it and let semantic analysis try - // to grok it and add the result to the ParamInfo we are building. - - // Inform the actions module about the parameter declarator, so it gets - // added to the current scope. - Action::TypeResult ParamTy = - Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); - - ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), - ParmDecl.getDeclSpec().TakeAttributes())); - } - - // If the next token is a comma, consume it and keep reading arguments. - if (Tok.isNot(tok::comma)) break; - - // Consume the comma. - ConsumeToken(); + ConsumeToken(); // Consume the ellipsis. + break; } - HasPrototype = true; + SourceLocation DSStart = Tok.getLocation(); - // Leave prototype scope. - ExitScope(); + // Parse the declaration-specifiers. + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + + // Parse the declarator. This is "PrototypeContext", because we must + // accept either 'declarator' or 'abstract-declarator' here. + Declarator ParmDecl(DS, Declarator::PrototypeContext); + ParseDeclarator(ParmDecl); + + // Parse GNU attributes, if present. + if (Tok.is(tok::kw___attribute)) + ParmDecl.AddAttributes(ParseAttributes()); + + // Verify C99 6.7.5.3p2: The only SCS allowed is '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(); + } + + // Remember this parsed parameter in ParamInfo. + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + + // Verify that the argument identifier has not already been mentioned. + if (ParmII && !ParamsSoFar.insert(ParmII)) { + Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition, + ParmII->getName()); + ParmII = 0; + ParmDecl.setInvalidType(true); + } + + // If no parameter was specified, verify that *something* was specified, + // otherwise we have a missing type and identifier. + if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && + ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) { + // Completely missing, emit error. + Diag(DSStart, diag::err_missing_param); + } else { + // Otherwise, we have something. Add it and let semantic analysis try + // to grok it and add the result to the ParamInfo we are building. + + // Inform the actions module about the parameter declarator, so it gets + // added to the current scope. + Action::TypeResult ParamTy = + Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); + + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), + ParmDecl.getDeclSpec().TakeAttributes())); + } + + // If the next token is a comma, consume it and keep reading arguments. + if (Tok.isNot(tok::comma)) break; + + // Consume the comma. + ConsumeToken(); } + // Leave prototype scope. + ExitScope(); + // Remember that we parsed a function type, and remember the attributes. - if (!ErrorEmitted) - D.AddTypeInfo(DeclaratorChunk::getFunction(HasPrototype, IsVariadic, - &ParamInfo[0], ParamInfo.size(), - LParenLoc)); + D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, + &ParamInfo[0], ParamInfo.size(), + LParenLoc)); // If we have the closing ')', eat it and we're done. - if (Tok.is(tok::r_paren)) { - ConsumeParen(); - } else { - // If an error happened earlier parsing something else in the proto, don't - // issue another error. - if (!ErrorEmitted) - Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren); - } + MatchRHSPunctuation(tok::r_paren, LParenLoc); }