diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp | 113 |
1 files changed, 101 insertions, 12 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp index a413f9a94148..ad0a15b0c8a6 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp @@ -202,9 +202,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { } } - if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype, - tok::annot_template_id) && - TryAnnotateCXXScopeToken()) + if (TryAnnotateOptionalCXXScopeToken()) return TPResult::Error; if (Tok.is(tok::annot_cxxscope)) ConsumeAnnotationToken(); @@ -785,9 +783,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, Parser::TPResult Parser::TryParsePtrOperatorSeq() { while (true) { - if (Tok.isOneOf(tok::coloncolon, tok::identifier)) - if (TryAnnotateCXXScopeToken(true)) - return TPResult::Error; + if (TryAnnotateOptionalCXXScopeToken(true)) + return TPResult::Error; if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { @@ -1031,6 +1028,10 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // direct-declarator '[' constant-expression[opt] ']' // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' TPR = TryParseBracketDeclarator(); + } else if (Tok.is(tok::kw_requires)) { + // declarator requires-clause + // A requires clause indicates a function declaration. + TPR = TPResult::True; } else { break; } @@ -1193,7 +1194,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<TentativeParseCCC>(*this); + return std::make_unique<TentativeParseCCC>(*this); } }; } @@ -1312,6 +1313,18 @@ public: Parser::TPResult Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, bool *InvalidAsDeclSpec) { + auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId, + int Lookahead) { + // We have a placeholder-constraint (we check for 'auto' or 'decltype' to + // distinguish 'C<int>;' from 'C<int> auto c = 1;') + return TemplateId->Kind == TNK_Concept_template && + GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype, + // If we have an identifier here, the user probably forgot the + // 'auto' in the placeholder constraint, e.g. 'C<int> x = 2;' + // This will be diagnosed nicely later, so disambiguate as a + // declaration. + tok::identifier); + }; switch (Tok.getKind()) { case tok::identifier: { // Check for need to substitute AltiVec __vector keyword @@ -1330,7 +1343,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // this is ambiguous. Typo-correct to type and expression keywords and // to types and identifiers, in order to try to recover from errors. TentativeParseCCC CCC(Next); - switch (TryAnnotateName(false /* no nested name specifier */, &CCC)) { + switch (TryAnnotateName(&CCC)) { case ANK_Error: return TPResult::Error; case ANK_TentativeDecl: @@ -1408,6 +1421,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_typedef: case tok::kw_constexpr: case tok::kw_consteval: + case tok::kw_constinit: // storage-class-specifier case tok::kw_register: case tok::kw_static: @@ -1514,10 +1528,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *InvalidAsDeclSpec = NextToken().is(tok::l_paren); return TPResult::Ambiguous; } + if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0)) + return TPResult::True; if (TemplateId->Kind != TNK_Type_template) return TPResult::False; CXXScopeSpec SS; - AnnotateTemplateIdTokenAsType(); + AnnotateTemplateIdTokenAsType(SS); assert(Tok.is(tok::annot_typename)); goto case_typename; } @@ -1527,6 +1543,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (TryAnnotateTypeOrScopeToken()) return TPResult::Error; if (!Tok.is(tok::annot_typename)) { + if (Tok.is(tok::annot_cxxscope) && + NextToken().is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = + takeTemplateIdAnnotation(NextToken()); + if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1)) + return TPResult::True; + } // 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)) { @@ -1568,7 +1591,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, } else { // Try to resolve the name. If it doesn't exist, assume it was // intended to name a type and keep disambiguating. - switch (TryAnnotateName(false /* SS is not dependent */)) { + switch (TryAnnotateName()) { case ANK_Error: return TPResult::Error; case ANK_TentativeDecl: @@ -2013,7 +2036,6 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, /// 'throw' '(' type-id-list[opt] ')' /// Parser::TPResult Parser::TryParseFunctionDeclarator() { - // The '(' is already parsed. TPResult TPR = TryParseParameterDeclarationClause(); @@ -2065,9 +2087,21 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { /// Parser::TPResult Parser::TryParseBracketDeclarator() { ConsumeBracket(); - if (!SkipUntil(tok::r_square, StopAtSemi)) + + // A constant-expression cannot begin with a '{', but the + // expr-or-braced-init-list of a postfix-expression can. + if (Tok.is(tok::l_brace)) + return TPResult::False; + + if (!SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch)) return TPResult::Error; + // If we hit a comma before the ']', this is not a constant-expression, + // but might still be the expr-or-braced-init-list of a postfix-expression. + if (Tok.isNot(tok::r_square)) + return TPResult::False; + + ConsumeBracket(); return TPResult::Ambiguous; } @@ -2121,3 +2155,58 @@ Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) { return TPResult::Ambiguous; return TPResult::False; } + +/// Determine whether we might be looking at the '(' of a C++20 explicit(bool) +/// in an earlier language mode. +Parser::TPResult Parser::isExplicitBool() { + assert(Tok.is(tok::l_paren) && "expected to be looking at a '(' token"); + + RevertingTentativeParsingAction PA(*this); + ConsumeParen(); + + // We can only have 'explicit' on a constructor, conversion function, or + // deduction guide. The declarator of a deduction guide cannot be + // parenthesized, so we know this isn't a deduction guide. So the only + // thing we need to check for is some number of parens followed by either + // the current class name or 'operator'. + while (Tok.is(tok::l_paren)) + ConsumeParen(); + + if (TryAnnotateOptionalCXXScopeToken()) + return TPResult::Error; + + // Class-scope constructor and conversion function names can't really be + // qualified, but we get better diagnostics if we assume they can be. + CXXScopeSpec SS; + if (Tok.is(tok::annot_cxxscope)) { + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + ConsumeAnnotationToken(); + } + + // 'explicit(operator' might be explicit(bool) or the declaration of a + // conversion function, but it's probably a conversion function. + if (Tok.is(tok::kw_operator)) + return TPResult::Ambiguous; + + // If this can't be a constructor name, it can only be explicit(bool). + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + return TPResult::True; + if (!Actions.isCurrentClassName(Tok.is(tok::identifier) + ? *Tok.getIdentifierInfo() + : *takeTemplateIdAnnotation(Tok)->Name, + getCurScope(), &SS)) + return TPResult::True; + // Formally, we must have a right-paren after the constructor name to match + // the grammar for a constructor. But clang permits a parenthesized + // constructor declarator, so also allow a constructor declarator to follow + // with no ')' token after the constructor name. + if (!NextToken().is(tok::r_paren) && + !isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(), + /*DeductionGuide=*/false)) + return TPResult::True; + + // Might be explicit(bool) or a parenthesized constructor name. + return TPResult::Ambiguous; +} |
