diff options
author | Guy Benyei <guy.benyei@intel.com> | 2012-12-18 12:30:03 +0000 |
---|---|---|
committer | Guy Benyei <guy.benyei@intel.com> | 2012-12-18 12:30:03 +0000 |
commit | 736104a7619c53ef92553780273d7357a3cdde81 (patch) | |
tree | a9f11d9747d4f6523e19cb83ae3a8ca3124f77af /lib/Parse/ParseTentative.cpp | |
parent | 15cc355526cdd898f5e528c38c3e385c45746e06 (diff) |
Add OpenCL images as clang builtin types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170428 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseTentative.cpp')
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 3154 |
1 files changed, 1580 insertions, 1574 deletions
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index b26181f08e..e411899ef4 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1,1574 +1,1580 @@ -//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the tentative parsing portions of the Parser -// interfaces, for ambiguity resolution. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/ParseDiagnostic.h" -#include "clang/Sema/ParsedTemplate.h" -using namespace clang; - -/// isCXXDeclarationStatement - C++-specialized function that disambiguates -/// between a declaration or an expression statement, when parsing function -/// bodies. Returns true for declaration, false for expression. -/// -/// declaration-statement: -/// block-declaration -/// -/// block-declaration: -/// simple-declaration -/// asm-definition -/// namespace-alias-definition -/// using-declaration -/// using-directive -/// [C++0x] static_assert-declaration -/// -/// asm-definition: -/// 'asm' '(' string-literal ')' ';' -/// -/// namespace-alias-definition: -/// 'namespace' identifier = qualified-namespace-specifier ';' -/// -/// using-declaration: -/// 'using' typename[opt] '::'[opt] nested-name-specifier -/// unqualified-id ';' -/// 'using' '::' unqualified-id ; -/// -/// using-directive: -/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt] -/// namespace-name ';' -/// -bool Parser::isCXXDeclarationStatement() { - switch (Tok.getKind()) { - // asm-definition - case tok::kw_asm: - // namespace-alias-definition - case tok::kw_namespace: - // using-declaration - // using-directive - case tok::kw_using: - // static_assert-declaration - case tok::kw_static_assert: - case tok::kw__Static_assert: - return true; - // simple-declaration - default: - return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); - } -} - -/// isCXXSimpleDeclaration - C++-specialized function that disambiguates -/// between a simple-declaration or an expression-statement. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. -/// Returns false if the statement is disambiguated as expression. -/// -/// simple-declaration: -/// decl-specifier-seq init-declarator-list[opt] ';' -/// -/// (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 - // conversion (5.2.3) as its leftmost subexpression can be indistinguishable - // from a declaration where the first declarator starts with a '('. In those - // cases the statement is a declaration. [Note: To disambiguate, the whole - // statement might have to be examined to determine if it is an - // expression-statement or a declaration]. - - // C++ 6.8p3: - // The disambiguation is purely syntactic; that is, the meaning of the names - // occurring in such a statement, beyond whether they are type-names or not, - // is not generally used in or changed by the disambiguation. Class - // templates are instantiated as necessary to determine if a qualified name - // is a type-name. Disambiguation precedes parsing, and a statement - // disambiguated as a declaration may be an ill-formed declaration. - - // We don't have to parse all of the decl-specifier-seq part. There's only - // an ambiguity if the first decl-specifier is - // simple-type-specifier/typename-specifier followed by a '(', which may - // indicate a function-style cast expression. - // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such - // a case. - - bool InvalidAsDeclaration = false; - TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), - &InvalidAsDeclaration); - if (TPR != TPResult::Ambiguous()) - return TPR != TPResult::False(); // Returns true for TPResult::True() or - // TPResult::Error(). - - // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer, - // and so gets some cases wrong. We can't carry on if we've already seen - // something which makes this statement invalid as a declaration in this case, - // since it can cause us to misparse valid code. Revisit this once - // TryParseInitDeclaratorList is fixed. - if (InvalidAsDeclaration) - return false; - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). - - // Ok, we have a simple-type-specifier/typename-specifier followed by a '(', - // or an identifier which doesn't resolve as anything. We need tentative - // parsing... - - TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(AllowForRangeDecl); - PA.Revert(); - - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - return true; - - // Declarations take precedence over expressions. - if (TPR == TPResult::Ambiguous()) - TPR = TPResult::True(); - - assert(TPR == TPResult::True() || TPR == TPResult::False()); - return TPR == TPResult::True(); -} - -/// simple-declaration: -/// decl-specifier-seq init-declarator-list[opt] ';' -/// -/// (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) { - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - - // Two decl-specifiers in a row conclusively disambiguate this as being a - // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the - // overwhelmingly common case that the next token is a '('. - if (Tok.isNot(tok::l_paren)) { - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR == TPResult::Ambiguous()) - return TPResult::True(); - if (TPR == TPResult::True() || TPR == TPResult::Error()) - return TPR; - assert(TPR == TPResult::False()); - } - - TPResult TPR = TryParseInitDeclaratorList(); - if (TPR != TPResult::Ambiguous()) - return TPR; - - if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) - return TPResult::False(); - - return TPResult::Ambiguous(); -} - -/// init-declarator-list: -/// init-declarator -/// init-declarator-list ',' init-declarator -/// -/// init-declarator: -/// declarator initializer[opt] -/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt] -/// -/// initializer: -/// '=' initializer-clause -/// '(' expression-list ')' -/// -/// initializer-clause: -/// assignment-expression -/// '{' initializer-list ','[opt] '}' -/// '{' '}' -/// -Parser::TPResult Parser::TryParseInitDeclaratorList() { - while (1) { - // declarator - TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); - if (TPR != TPResult::Ambiguous()) - return TPR; - - // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) - return TPResult::True(); - - // initializer[opt] - if (Tok.is(tok::l_paren)) { - // Parse through the parens. - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error(); - } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { - // MSVC and g++ won't examine the rest of declarators if '=' is - // encountered; they just conclude that we have a declaration. - // EDG parses the initializer completely, which is the proper behavior - // for this case. - // - // At present, Clang follows MSVC and g++, since the parser does not have - // the ability to parse an expression fully without recording the - // results of that parse. - // Also allow 'in' after on objective-c declaration as in: - // for (int (^b)(void) in array). Ideally this should be done in the - // context of parsing for-init-statement of a foreach statement only. But, - // in any other context 'in' is invalid after a declaration and parser - // issues the error regardless of outcome of this decision. - // FIXME. Change if above assumption does not hold. - return TPResult::True(); - } - - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // the comma. - } - - return TPResult::Ambiguous(); -} - -/// isCXXConditionDeclaration - Disambiguates between a declaration or an -/// expression for a condition of a if/switch/while/for statement. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. -/// -/// 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 -/// -bool Parser::isCXXConditionDeclaration() { - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR != TPResult::Ambiguous()) - return TPR != TPResult::False(); // Returns true for TPResult::True() or - // TPResult::Error(). - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). - - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... - - TentativeParsingAction PA(*this); - - // type-specifier-seq - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - assert(Tok.is(tok::l_paren) && "Expected '('"); - - // declarator - TPR = TryParseDeclarator(false/*mayBeAbstract*/); - - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - TPR = TPResult::True(); - - if (TPR == TPResult::Ambiguous()) { - // '=' - // [GNU] simple-asm-expr[opt] attributes[opt] - 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(); - } - - PA.Revert(); - - assert(TPR == TPResult::True() || TPR == TPResult::False()); - return TPR == TPResult::True(); -} - - /// \brief Determine whether the next set of tokens contains a type-id. - /// - /// The context parameter states what context we're parsing right - /// now, which affects how this routine copes with the token - /// following the type-id. If the context is TypeIdInParens, we have - /// already parsed the '(' and we will cease lookahead when we hit - /// the corresponding ')'. If the context is - /// TypeIdAsTemplateArgument, we've already parsed the '<' or ',' - /// before this template argument, and will cease lookahead when we - /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id - /// and false for an expression. If during the disambiguation - /// process a parsing error is encountered, the function returns - /// true to let the declaration parsing code handle it. - /// - /// type-id: - /// type-specifier-seq abstract-declarator[opt] - /// -bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { - - isAmbiguous = false; - - // C++ 8.2p2: - // The ambiguity arising from the similarity between a function-style cast and - // a type-id can occur in different contexts. The ambiguity appears as a - // choice between a function-style cast expression and a declaration of a - // type. The resolution is that any construct that could possibly be a type-id - // in its syntactic context shall be considered a type-id. - - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR != TPResult::Ambiguous()) - return TPR != TPResult::False(); // Returns true for TPResult::True() or - // TPResult::Error(). - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). - - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... - - TentativeParsingAction PA(*this); - - // type-specifier-seq - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - - assert(Tok.is(tok::l_paren) && "Expected '('"); - - // declarator - TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); - - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - TPR = TPResult::True(); - - if (TPR == TPResult::Ambiguous()) { - // We are supposed to be inside parens, so if after the abstract declarator - // we encounter a ')' this is a type-id, otherwise it's an expression. - if (Context == TypeIdInParens && Tok.is(tok::r_paren)) { - TPR = TPResult::True(); - isAmbiguous = true; - - // We are supposed to be inside a template argument, so if after - // the abstract declarator we encounter a '>', '>>' (in C++0x), or - // ',', this is a type-id. Otherwise, it's an expression. - } else if (Context == TypeIdAsTemplateArgument && - (Tok.is(tok::greater) || Tok.is(tok::comma) || - (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) { - TPR = TPResult::True(); - isAmbiguous = true; - - } else - TPR = TPResult::False(); - } - - PA.Revert(); - - assert(TPR == TPResult::True() || TPR == TPResult::False()); - return TPR == TPResult::True(); -} - -/// \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 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. -/// -/// C++11 [dcl.attr.grammar]: -/// -/// attribute-specifier: -/// '[' '[' attribute-list ']' ']' -/// alignment-specifier -/// -/// attribute-list: -/// attribute[opt] -/// attribute-list ',' attribute[opt] -/// attribute '...' -/// attribute-list ',' attribute '...' -/// -/// attribute: -/// attribute-token attribute-argument-clause[opt] -/// -/// attribute-token: -/// identifier -/// identifier '::' identifier -/// -/// attribute-argument-clause: -/// '(' balanced-token-seq ')' -Parser::CXX11AttributeKind -Parser::isCXX11AttributeSpecifier(bool Disambiguate, - bool OuterMightBeMessageSend) { - if (Tok.is(tok::kw_alignas)) - return CAK_AttributeSpecifier; - - if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) - return CAK_NotAttributeSpecifier; - - // 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(); - - // 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; - } - - ConsumeBracket(); - - // 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; - } - } - - // 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: -/// direct-declarator -/// ptr-operator declarator -/// -/// direct-declarator: -/// declarator-id -/// direct-declarator '(' parameter-declaration-clause ')' -/// cv-qualifier-seq[opt] exception-specification[opt] -/// direct-declarator '[' constant-expression[opt] ']' -/// '(' declarator ')' -/// [GNU] '(' attributes declarator ')' -/// -/// abstract-declarator: -/// ptr-operator abstract-declarator[opt] -/// direct-abstract-declarator -/// ... -/// -/// direct-abstract-declarator: -/// direct-abstract-declarator[opt] -/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] -/// exception-specification[opt] -/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']' -/// '(' abstract-declarator ')' -/// -/// ptr-operator: -/// '*' cv-qualifier-seq[opt] -/// '&' -/// [C++0x] '&&' [TODO] -/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] -/// -/// cv-qualifier-seq: -/// cv-qualifier cv-qualifier-seq[opt] -/// -/// cv-qualifier: -/// 'const' -/// 'volatile' -/// -/// declarator-id: -/// '...'[opt] id-expression -/// -/// id-expression: -/// unqualified-id -/// qualified-id [TODO] -/// -/// unqualified-id: -/// identifier -/// operator-function-id [TODO] -/// conversion-function-id [TODO] -/// '~' class-name [TODO] -/// template-id [TODO] -/// -Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, - bool mayHaveIdentifier) { - // declarator: - // direct-declarator - // ptr-operator declarator - - while (1) { - if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) - if (TryAnnotateCXXScopeToken(true)) - return TPResult::Error(); - - if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || - Tok.is(tok::ampamp) || - (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { - // ptr-operator - ConsumeToken(); - while (Tok.is(tok::kw_const) || - Tok.is(tok::kw_volatile) || - Tok.is(tok::kw_restrict)) - ConsumeToken(); - } else { - break; - } - } - - // direct-declarator: - // direct-abstract-declarator: - if (Tok.is(tok::ellipsis)) - ConsumeToken(); - - if ((Tok.is(tok::identifier) || - (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && - mayHaveIdentifier) { - // declarator-id - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - else - TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); - } else if (Tok.is(tok::l_paren)) { - ConsumeParen(); - if (mayBeAbstract && - (Tok.is(tok::r_paren) || // '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] - TPResult TPR = TryParseFunctionDeclarator(); - if (TPR != TPResult::Ambiguous()) - return TPR; - } else { - // '(' declarator ')' - // '(' attributes declarator ')' - // '(' abstract-declarator ')' - if (Tok.is(tok::kw___attribute) || - Tok.is(tok::kw___declspec) || - Tok.is(tok::kw___cdecl) || - Tok.is(tok::kw___stdcall) || - Tok.is(tok::kw___fastcall) || - Tok.is(tok::kw___thiscall) || - Tok.is(tok::kw___unaligned)) - return TPResult::True(); // attributes indicate declaration - TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); - if (TPR != TPResult::Ambiguous()) - return TPR; - if (Tok.isNot(tok::r_paren)) - return TPResult::False(); - ConsumeParen(); - } - } else if (!mayBeAbstract) { - return TPResult::False(); - } - - while (1) { - TPResult TPR(TPResult::Ambiguous()); - - // abstract-declarator: ... - if (Tok.is(tok::ellipsis)) - ConsumeToken(); - - if (Tok.is(tok::l_paren)) { - // Check whether we have a function declarator or a possible ctor-style - // initializer that follows the declarator. Note that ctor-style - // initializers are not possible in contexts where abstract declarators - // are allowed. - if (!mayBeAbstract && !isCXXFunctionDeclarator()) - break; - - // direct-declarator '(' parameter-declaration-clause ')' - // cv-qualifier-seq[opt] exception-specification[opt] - ConsumeParen(); - TPR = TryParseFunctionDeclarator(); - } else if (Tok.is(tok::l_square)) { - // direct-declarator '[' constant-expression[opt] ']' - // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' - TPR = TryParseBracketDeclarator(); - } else { - break; - } - - if (TPR != TPResult::Ambiguous()) - return TPR; - } - - return TPResult::Ambiguous(); -} - -Parser::TPResult -Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { - switch (Kind) { - // Obviously starts an expression. - case tok::numeric_constant: - case tok::char_constant: - case tok::wide_char_constant: - case tok::utf16_char_constant: - case tok::utf32_char_constant: - case tok::string_literal: - case tok::wide_string_literal: - case tok::utf8_string_literal: - case tok::utf16_string_literal: - case tok::utf32_string_literal: - case tok::l_square: - case tok::l_paren: - case tok::amp: - case tok::ampamp: - case tok::star: - case tok::plus: - case tok::plusplus: - case tok::minus: - case tok::minusminus: - case tok::tilde: - case tok::exclaim: - case tok::kw_sizeof: - case tok::kw___func__: - case tok::kw_const_cast: - case tok::kw_delete: - case tok::kw_dynamic_cast: - case tok::kw_false: - case tok::kw_new: - case tok::kw_operator: - case tok::kw_reinterpret_cast: - case tok::kw_static_cast: - case tok::kw_this: - case tok::kw_throw: - case tok::kw_true: - case tok::kw_typeid: - case tok::kw_alignof: - case tok::kw_noexcept: - case tok::kw_nullptr: - case tok::kw__Alignof: - case tok::kw___null: - case tok::kw___alignof: - case tok::kw___builtin_choose_expr: - case tok::kw___builtin_offsetof: - case tok::kw___builtin_types_compatible_p: - case tok::kw___builtin_va_arg: - case tok::kw___imag: - case tok::kw___real: - case tok::kw___FUNCTION__: - case tok::kw_L__FUNCTION__: - case tok::kw___PRETTY_FUNCTION__: - case tok::kw___has_nothrow_assign: - case tok::kw___has_nothrow_copy: - case tok::kw___has_nothrow_constructor: - case tok::kw___has_trivial_assign: - case tok::kw___has_trivial_copy: - case tok::kw___has_trivial_constructor: - case tok::kw___has_trivial_destructor: - case tok::kw___has_virtual_destructor: - case tok::kw___is_abstract: - case tok::kw___is_base_of: - case tok::kw___is_class: - case tok::kw___is_convertible_to: - case tok::kw___is_empty: - case tok::kw___is_enum: - case tok::kw___is_interface_class: - 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: - return TPResult::True(); - - // Obviously starts a type-specifier-seq: - case tok::kw_char: - case tok::kw_const: - case tok::kw_double: - case tok::kw_enum: - case tok::kw_half: - case tok::kw_float: - 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: - case tok::kw_struct: - case tok::kw_union: - case tok::kw_unsigned: - case tok::kw_void: - case tok::kw_volatile: - case tok::kw__Bool: - case tok::kw__Complex: - case tok::kw_class: - case tok::kw_typename: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw___underlying_type: - case tok::kw_thread_local: - case tok::kw__Decimal32: - case tok::kw__Decimal64: - case tok::kw__Decimal128: - case tok::kw___thread: - case tok::kw_typeof: - case tok::kw___cdecl: - case tok::kw___stdcall: - case tok::kw___fastcall: - case tok::kw___thiscall: - case tok::kw___unaligned: - case tok::kw___vector: - case tok::kw___pixel: - case tok::kw__Atomic: - case tok::kw___unknown_anytype: - return TPResult::False(); - - default: - break; - } - - return TPResult::Ambiguous(); -} - -bool Parser::isTentativelyDeclared(IdentifierInfo *II) { - return std::find(TentativelyDeclaredIdentifiers.begin(), - TentativelyDeclaredIdentifiers.end(), II) - != TentativelyDeclaredIdentifiers.end(); -} - -/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration -/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could -/// be either a decl-specifier or a function-style cast, and TPResult::Error() -/// if a parsing error was found and reported. -/// -/// If HasMissingTypename is provided, a name with a dependent scope specifier -/// will be treated as ambiguous if the 'typename' keyword is missing. If this -/// happens, *HasMissingTypename will be set to 'true'. This will also be used -/// as an indicator that undeclared identifiers (which will trigger a later -/// parse error) should be treated as types. Returns TPResult::Ambiguous() in -/// such cases. -/// -/// decl-specifier: -/// storage-class-specifier -/// type-specifier -/// function-specifier -/// 'friend' -/// 'typedef' -/// [C++0x] 'constexpr' -/// [GNU] attributes declaration-specifiers[opt] -/// -/// storage-class-specifier: -/// 'register' -/// 'static' -/// 'extern' -/// 'mutable' -/// 'auto' -/// [GNU] '__thread' -/// -/// function-specifier: -/// 'inline' -/// 'virtual' -/// 'explicit' -/// -/// typedef-name: -/// identifier -/// -/// type-specifier: -/// simple-type-specifier -/// class-specifier -/// enum-specifier -/// elaborated-type-specifier -/// typename-specifier -/// cv-qualifier -/// -/// simple-type-specifier: -/// '::'[opt] nested-name-specifier[opt] type-name -/// '::'[opt] nested-name-specifier 'template' -/// simple-template-id [TODO] -/// 'char' -/// 'wchar_t' -/// 'bool' -/// 'short' -/// 'int' -/// 'long' -/// 'signed' -/// 'unsigned' -/// 'float' -/// 'double' -/// 'void' -/// [GNU] typeof-specifier -/// [GNU] '_Complex' -/// [C++0x] 'auto' [TODO] -/// [C++0x] 'decltype' ( expression ) -/// -/// type-name: -/// class-name -/// enum-name -/// typedef-name -/// -/// elaborated-type-specifier: -/// class-key '::'[opt] nested-name-specifier[opt] identifier -/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt] -/// simple-template-id -/// 'enum' '::'[opt] nested-name-specifier[opt] identifier -/// -/// enum-name: -/// identifier -/// -/// enum-specifier: -/// 'enum' identifier[opt] '{' enumerator-list[opt] '}' -/// 'enum' identifier[opt] '{' enumerator-list ',' '}' -/// -/// class-specifier: -/// class-head '{' member-specification[opt] '}' -/// -/// class-head: -/// class-key identifier[opt] base-clause[opt] -/// class-key nested-name-specifier identifier base-clause[opt] -/// class-key nested-name-specifier[opt] simple-template-id -/// base-clause[opt] -/// -/// class-key: -/// 'class' -/// 'struct' -/// 'union' -/// -/// cv-qualifier: -/// 'const' -/// 'volatile' -/// [GNU] restrict -/// -Parser::TPResult -Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, - bool *HasMissingTypename) { - switch (Tok.getKind()) { - case tok::identifier: { - // Check for need to substitute AltiVec __vector keyword - // for "vector" identifier. - if (TryAltiVecVectorToken()) - return TPResult::True(); - - const Token &Next = NextToken(); - // In 'foo bar', 'foo' is always a type name outside of Objective-C. - if (!getLangOpts().ObjC1 && Next.is(tok::identifier)) - return TPResult::True(); - - if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { - // Determine whether this is a valid expression. If not, we will hit - // a parse error one way or another. In that case, tell the caller that - // this is ambiguous. Typo-correct to type and expression keywords and - // to types and identifiers, in order to try to recover from errors. - CorrectionCandidateCallback TypoCorrection; - TypoCorrection.WantRemainingKeywords = false; - switch (TryAnnotateName(false /* no nested name specifier */, - &TypoCorrection)) { - case ANK_Error: - return TPResult::Error(); - case ANK_TentativeDecl: - return TPResult::False(); - case ANK_TemplateName: - // A bare type template-name which can't be a template template - // argument is an error, and was probably intended to be a type. - return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); - case ANK_Unresolved: - return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False(); - case ANK_Success: - break; - } - assert(Tok.isNot(tok::identifier) && - "TryAnnotateName succeeded without producing an annotation"); - } else { - // This might possibly be a type with a dependent scope specifier and - // a missing 'typename' keyword. Don't use TryAnnotateName in this case, - // since it will annotate as a primary expression, and we want to use the - // "missing 'typename'" logic. - if (TryAnnotateTypeOrScopeToken()) - return TPResult::Error(); - // If annotation failed, assume it's a non-type. - // FIXME: If this happens due to an undeclared identifier, treat it as - // ambiguous. - if (Tok.is(tok::identifier)) - return TPResult::False(); |