diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp | 331 |
1 files changed, 239 insertions, 92 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index d53839f..28c5e8b 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -62,7 +62,7 @@ bool Parser::isCXXDeclarationStatement() { return true; // simple-declaration default: - return isCXXSimpleDeclaration(); + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); } } @@ -75,7 +75,11 @@ bool Parser::isCXXDeclarationStatement() { /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// -bool Parser::isCXXSimpleDeclaration() { +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // C++ 6.8p1: // There is an ambiguity in the grammar involving expression-statements and // declarations: An expression-statement with a function-style explicit type @@ -112,7 +116,7 @@ bool Parser::isCXXSimpleDeclaration() { // We need tentative parsing... TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); PA.Revert(); // In case of an error, let the declaration parsing code handle it. @@ -130,7 +134,12 @@ bool Parser::isCXXSimpleDeclaration() { /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// -Parser::TPResult Parser::TryParseSimpleDeclaration() { +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +/// +Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { // We know that we have a simple-type-specifier/typename-specifier followed // by a '('. assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous()); @@ -140,7 +149,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } @@ -150,7 +159,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { if (TPR != TPResult::Ambiguous()) return TPR; - if (Tok.isNot(tok::semi)) + if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) return TPResult::False(); return TPResult::Ambiguous(); @@ -224,6 +233,8 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression +/// [C++11] type-specifier-seq declarator '=' initializer-clause +/// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// @@ -247,7 +258,7 @@ bool Parser::isCXXConditionDeclaration() { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } assert(Tok.is(tok::l_paren) && "Expected '('"); @@ -265,6 +276,8 @@ bool Parser::isCXXConditionDeclaration() { if (Tok.is(tok::equal) || Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) TPR = TPResult::True(); + else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) + TPR = TPResult::True(); else TPR = TPResult::False(); } @@ -322,7 +335,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } @@ -347,7 +360,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // ',', this is a type-id. Otherwise, it's an expression. } else if (Context == TypeIdAsTemplateArgument && (Tok.is(tok::greater) || Tok.is(tok::comma) || - (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) { + (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) { TPR = TPResult::True(); isAmbiguous = true; @@ -361,91 +374,166 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { return TPR == TPResult::True(); } -/// isCXX0XAttributeSpecifier - returns true if this is a C++0x -/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is -/// performed that will simply return true if a [[ is seen. Currently C++ has no -/// syntactical ambiguities from this check, but it may inhibit error recovery. -/// If CheckClosing is true, a check is made for closing ]] brackets. +/// \brief Returns true if this is a C++11 attribute-specifier. Per +/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens +/// always introduce an attribute. In Objective-C++11, this rule does not +/// apply if either '[' begins a message-send. +/// +/// If Disambiguate is true, we try harder to determine whether a '[[' starts +/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not. /// -/// If given, After is set to the token after the attribute-specifier so that -/// appropriate parsing decisions can be made; it is left untouched if false is -/// returned. +/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an +/// Obj-C message send or the start of an attribute. Otherwise, we assume it +/// is not an Obj-C message send. /// -/// FIXME: If an error is in the closing ]] brackets, the program assumes -/// the absence of an attribute-specifier, which can cause very yucky errors -/// to occur. +/// C++11 [dcl.attr.grammar]: /// -/// [C++0x] attribute-specifier: +/// attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// -/// [C++0x] attribute-list: +/// attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' /// -/// [C++0x] attribute: +/// attribute: /// attribute-token attribute-argument-clause[opt] /// -/// [C++0x] attribute-token: -/// identifier -/// attribute-scoped-token -/// -/// [C++0x] attribute-scoped-token: -/// attribute-namespace '::' identifier -/// -/// [C++0x] attribute-namespace: +/// attribute-token: /// identifier +/// identifier '::' identifier /// -/// [C++0x] attribute-argument-clause: +/// attribute-argument-clause: /// '(' balanced-token-seq ')' -/// -/// [C++0x] balanced-token-seq: -/// balanced-token -/// balanced-token-seq balanced-token -/// -/// [C++0x] balanced-token: -/// '(' balanced-token-seq ')' -/// '[' balanced-token-seq ']' -/// '{' balanced-token-seq '}' -/// any token but '(', ')', '[', ']', '{', or '}' -bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, - tok::TokenKind *After) { +Parser::CXX11AttributeKind +Parser::isCXX11AttributeSpecifier(bool Disambiguate, + bool OuterMightBeMessageSend) { if (Tok.is(tok::kw_alignas)) - return true; + return CAK_AttributeSpecifier; if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) - return false; - - // No tentative parsing if we don't need to look for ]] - if (!CheckClosing && !getLang().ObjC1) - return true; - - struct TentativeReverter { - TentativeParsingAction PA; + return CAK_NotAttributeSpecifier; - TentativeReverter (Parser& P) - : PA(P) - {} - ~TentativeReverter () { - PA.Revert(); - } - } R(*this); + // No tentative parsing if we don't need to look for ']]' or a lambda. + if (!Disambiguate && !getLangOpts().ObjC1) + return CAK_AttributeSpecifier; + + TentativeParsingAction PA(*this); // Opening brackets were checked for above. ConsumeBracket(); - ConsumeBracket(); - // SkipUntil will handle balanced tokens, which are guaranteed in attributes. - SkipUntil(tok::r_square, false); + // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. + if (!getLangOpts().ObjC1) { + ConsumeBracket(); + + bool IsAttribute = SkipUntil(tok::r_square, false); + IsAttribute &= Tok.is(tok::r_square); + + PA.Revert(); + + return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; + } + + // In Obj-C++11, we need to distinguish four situations: + // 1a) int x[[attr]]; C++11 attribute. + // 1b) [[attr]]; C++11 statement attribute. + // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index. + // 3a) int x[[obj get]]; Message send in array size/index. + // 3b) [[Class alloc] init]; Message send in message send. + // 4) [[obj]{ return self; }() doStuff]; Lambda in message send. + // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted. + + // If we have a lambda-introducer, then this is definitely not a message send. + // FIXME: If this disambiguation is too slow, fold the tentative lambda parse + // into the tentative attribute parse below. + LambdaIntroducer Intro; + if (!TryParseLambdaIntroducer(Intro)) { + // A lambda cannot end with ']]', and an attribute must. + bool IsAttribute = Tok.is(tok::r_square); + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 attribute. + return CAK_AttributeSpecifier; + + if (OuterMightBeMessageSend) + // Case 4: Lambda in message send. + return CAK_NotAttributeSpecifier; + + // Case 2: Lambda in array size / index. + return CAK_InvalidAttributeSpecifier; + } - if (Tok.isNot(tok::r_square)) - return false; ConsumeBracket(); - if (After) - *After = Tok.getKind(); + // If we don't have a lambda-introducer, then we have an attribute or a + // message-send. + bool IsAttribute = true; + while (Tok.isNot(tok::r_square)) { + if (Tok.is(tok::comma)) { + // Case 1: Stray commas can only occur in attributes. + PA.Revert(); + return CAK_AttributeSpecifier; + } + + // Parse the attribute-token, if present. + // C++11 [dcl.attr.grammar]: + // If a keyword or an alternative token that satisfies the syntactic + // requirements of an identifier is contained in an attribute-token, + // it is considered an identifier. + SourceLocation Loc; + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + } - return true; + // Parse the attribute-argument-clause, if present. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + if (!SkipUntil(tok::r_paren, false)) { + IsAttribute = false; + break; + } + } + + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + // An attribute must end ']]'. + if (IsAttribute) { + if (Tok.is(tok::r_square)) { + ConsumeBracket(); + IsAttribute = Tok.is(tok::r_square); + } else { + IsAttribute = false; + } + } + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 statement attribute. + return CAK_AttributeSpecifier; + + // Case 3: Message send. + return CAK_NotAttributeSpecifier; } /// declarator: @@ -540,7 +628,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, ConsumeParen(); if (mayBeAbstract && (Tok.is(tok::r_paren) || // 'int()' is a function. - Tok.is(tok::ellipsis) || // 'int(...)' is a function. + // 'int(...)' is a function. + (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || isDeclarationSpecifier())) { // 'int(int)' is a function. // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] // exception-specification[opt] @@ -670,11 +759,14 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: + case tok::kw___is_final: case tok::kw___is_literal: case tok::kw___is_literal_type: case tok::kw___is_pod: case tok::kw___is_polymorphic: case tok::kw___is_trivial: + case tok::kw___is_trivially_assignable: + case tok::kw___is_trivially_constructible: case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___uuidof: @@ -690,6 +782,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_int: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_restrict: case tok::kw_short: case tok::kw_signed: @@ -705,7 +798,6 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: - case tok::kw_decltype: case tok::kw___underlying_type: case tok::kw_thread_local: case tok::kw__Decimal32: @@ -825,7 +917,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// 'volatile' /// [GNU] restrict /// -Parser::TPResult Parser::isCXXDeclarationSpecifier() { +Parser::TPResult +Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { switch (Tok.getKind()) { case tok::identifier: // foo::bar // Check for need to substitute AltiVec __vector keyword @@ -840,21 +933,22 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { return TPResult::Error(); if (Tok.is(tok::identifier)) return TPResult::False(); - return isCXXDeclarationSpecifier(); + return isCXXDeclarationSpecifier(BracedCastResult); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); if (Next.is(tok::kw_new) || // ::new Next.is(tok::kw_delete)) // ::delete return TPResult::False(); - + } + // Fall through. + case tok::kw_decltype: // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - return isCXXDeclarationSpecifier(); - } - + return isCXXDeclarationSpecifier(BracedCastResult); + // decl-specifier: // storage-class-specifier // type-specifier @@ -940,8 +1034,31 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // We've already annotated a scope; try to annotate a type. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - if (!Tok.is(tok::annot_typename)) + if (!Tok.is(tok::annot_typename)) { + // If the next token is an identifier or a type qualifier, then this + // can't possibly be a valid expression either. + if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { + TentativeParsingAction PA(*this); + ConsumeToken(); + ConsumeToken(); + bool isIdentifier = Tok.is(tok::identifier); + TPResult TPR = TPResult::False(); + if (!isIdentifier) + TPR = isCXXDeclarationSpecifier(BracedCastResult); + PA.Revert(); + + if (isIdentifier || + TPR == TPResult::True() || TPR == TPResult::Error()) + return TPResult::Error(); + } + } return TPResult::False(); + } // If that succeeded, fallthrough into the generic simple-type-id case. // The ambiguity resides in a simple-type-specifier/typename-specifier @@ -965,13 +1082,14 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::annot_typename: case_typename: // In Objective-C, we might have a protocol-qualified type. - if (getLang().ObjC1 && NextToken().is(tok::less)) { + if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { // Tentatively parse the TentativeParsingAction PA(*this); ConsumeToken(); // The type token TPResult TPR = TryParseProtocolQualifiers(); bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); PA.Revert(); @@ -980,6 +1098,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (isFollowedByParen) return TPResult::Ambiguous(); + + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; return TPResult::True(); } @@ -993,15 +1114,26 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_int: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: + case tok::annot_decltype: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); + // This is a function-style cast in all cases we disambiguate other than + // one: + // struct S { + // enum E : int { a = 4 }; // enum + // enum E : int { 4 }; // bit-field + // }; + if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace)) + return BracedCastResult; + if (isStartOfObjCClassMessageMissingOpenBracket()) return TPResult::False(); @@ -1016,6 +1148,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { TPResult TPR = TryParseTypeofSpecifier(); bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); PA.Revert(); @@ -1025,18 +1158,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (isFollowedByParen) return TPResult::Ambiguous(); - return TPResult::True(); - } + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; - // C++0x decltype support. - case tok::kw_decltype: return TPResult::True(); + } // C++0x type traits support case tok::kw___underlying_type: return TPResult::True(); - // C1x _Atomic + // C11 _Atomic case tok::kw__Atomic: return TPResult::True(); @@ -1096,7 +1228,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } @@ -1160,11 +1292,13 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { /// parameter-declaration-list ',' parameter-declaration /// /// parameter-declaration: -/// decl-specifier-seq declarator attributes[opt] -/// decl-specifier-seq declarator attributes[opt] '=' assignment-expression -/// decl-specifier-seq abstract-declarator[opt] attributes[opt] -/// decl-specifier-seq abstract-declarator[opt] attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] /// '=' assignment-expression +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] '=' assignment-expression /// Parser::TPResult Parser::TryParseParameterDeclarationClause() { @@ -1182,13 +1316,23 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { // '...'[opt] if (Tok.is(tok::ellipsis)) { ConsumeToken(); - return TPResult::True(); // '...' is a sign of a function declarator. + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); } + // An attribute-specifier-seq here is a sign of a function declarator. + if (isCXX11AttributeSpecifier(/*Disambiguate*/false, + /*OuterMightBeMessageSend*/true)) + return TPResult::True(); + ParsedAttributes attrs(AttrFactory); MaybeParseMicrosoftAttributes(attrs); // decl-specifier-seq + // A parameter-declaration's initializer must be preceded by an '=', so + // decl-specifier-seq '{' is not a parameter in C++11. TPResult TPR = TryParseDeclarationSpecifier(); if (TPR != TPResult::Ambiguous()) return TPR; @@ -1206,14 +1350,17 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { if (Tok.is(tok::equal)) { // '=' assignment-expression // Parse through assignment-expression. - tok::TokenKind StopToks[2] ={ tok::comma, tok::r_paren }; - if (!SkipUntil(StopToks, 2, true/*StopAtSemi*/, true/*DontConsume*/)) + if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/, + true/*DontConsume*/)) return TPResult::Error(); } if (Tok.is(tok::ellipsis)) { ConsumeToken(); - return TPResult::True(); // '...' is a sign of a function declarator. + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); } if (Tok.isNot(tok::comma)) |