diff options
Diffstat (limited to 'clang/lib/Parse/ParseTentative.cpp')
| -rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 87 | 
1 files changed, 80 insertions, 7 deletions
| diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 4d69fb4693fb8..ad0a15b0c8a6d 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/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))) { @@ -1316,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 @@ -1519,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;    } @@ -1532,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)) { @@ -2137,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; +} | 
