diff options
Diffstat (limited to 'lib/Parse/ParseExprCXX.cpp')
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 168 |
1 files changed, 103 insertions, 65 deletions
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 85c1301fc9678..ca1b3b1ad01bb 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -100,48 +100,6 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /*AtDigraph*/false); } -/// \brief Emits an error for a left parentheses after a double colon. -/// -/// When a '(' is found after a '::', emit an error. Attempt to fix the token -/// stream by removing the '(', and the matching ')' if found. -void Parser::CheckForLParenAfterColonColon() { - if (!Tok.is(tok::l_paren)) - return; - - Token LParen = Tok; - Token NextTok = GetLookAheadToken(1); - Token StarTok = NextTok; - // Check for (identifier or (*identifier - Token IdentifierTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : StarTok; - if (IdentifierTok.isNot(tok::identifier)) - return; - // Eat the '('. - ConsumeParen(); - Token RParen; - RParen.setLocation(SourceLocation()); - // Do we have a ')' ? - NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1); - if (NextTok.is(tok::r_paren)) { - RParen = NextTok; - // Eat the '*' if it is present. - if (StarTok.is(tok::star)) - ConsumeToken(); - // Eat the identifier. - ConsumeToken(); - // Add the identifier token back. - PP.EnterToken(IdentifierTok); - // Add the '*' back if it was present. - if (StarTok.is(tok::star)) - PP.EnterToken(StarTok); - // Eat the ')'. - ConsumeParen(); - } - - Diag(LParen.getLocation(), diag::err_paren_after_colon_colon) - << FixItHint::CreateRemoval(LParen.getLocation()) - << FixItHint::CreateRemoval(RParen.getLocation()); -} - /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -237,8 +195,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS)) return true; - CheckForLParenAfterColonColon(); - HasScopeSpecifier = true; } } @@ -427,13 +383,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // namespace-name '::' // nested-name-specifier identifier '::' Token Next = NextToken(); - + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), + ObjectType); + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { - if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II, - Tok.getLocation(), - Next.getLocation(), ObjectType, + if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, IdInfo, EnteringContext) && // If the token after the colon isn't an identifier, it's still an // error, but they probably meant something else strange so don't @@ -459,8 +415,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Next.is(tok::coloncolon)) { if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && - !Actions.isNonTypeNestedNameSpecifier( - getCurScope(), SS, Tok.getLocation(), II, ObjectType)) { + !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, IdInfo)) { *MayBePseudoDestructor = true; return false; } @@ -492,12 +447,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Token ColonColon = Tok; SourceLocation CCLoc = ConsumeToken(); - CheckForLParenAfterColonColon(); - bool IsCorrectedToColon = false; bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr; - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, - ObjectType, EnteringContext, SS, + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), IdInfo, + EnteringContext, SS, false, CorrectionFlagPtr)) { // Identifier is not recognized as a nested name, but we can have // mistyped '::' instead of ':'. @@ -949,6 +902,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, SourceLocation StartLoc = Tok.getLocation(); InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true); Init = ParseInitializer(); + if (!Init.isInvalid()) + Init = Actions.CorrectDelayedTyposInExpr(Init.get()); if (Tok.getLocation() != StartLoc) { // Back out the lexing of the token after the initializer. @@ -1003,6 +958,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // return y; // } // }; + // } // If x was not const, the second use would require 'L' to capture, and // that would be an error. @@ -1053,6 +1009,58 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { return false; } +static void +tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc, + SourceLocation &ConstexprLoc, + SourceLocation &DeclEndLoc) { + assert(MutableLoc.isInvalid()); + assert(ConstexprLoc.isInvalid()); + // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc + // to the final of those locations. Emit an error if we have multiple + // copies of those keywords and recover. + + while (true) { + switch (P.getCurToken().getKind()) { + case tok::kw_mutable: { + if (MutableLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + MutableLoc = P.ConsumeToken(); + DeclEndLoc = MutableLoc; + break /*switch*/; + } + case tok::kw_constexpr: + if (ConstexprLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + ConstexprLoc = P.ConsumeToken(); + DeclEndLoc = ConstexprLoc; + break /*switch*/; + default: + return; + } + } +} + +static void +addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc, + DeclSpec &DS) { + if (ConstexprLoc.isValid()) { + P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus1z + ? diag::ext_constexpr_on_lambda_cxx1z + : diag::warn_cxx14_compat_constexpr_on_lambda); + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + DS.SetConstexprSpec(ConstexprLoc, PrevSpec, DiagID); + assert(PrevSpec == nullptr && DiagID == 0 && + "Constexpr cannot have been set previously!"); + } +} + /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( @@ -1072,7 +1080,27 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - Actions.PushLambdaScope(); + Actions.PushLambdaScope(); + + ParsedAttributes Attr(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + if (getLangOpts().CUDA) { + // In CUDA code, GNU attributes are allowed to appear immediately after the + // "[...]", even if there is no "(...)" before the lambda body. + MaybeParseGNUAttributes(D); + } + + // Helper to emit a warning if we see a CUDA host/device/global attribute + // after '(...)'. nvcc doesn't accept this. + auto WarnIfHasCUDATargetAttr = [&] { + if (getLangOpts().CUDA) + for (auto *A = Attr.getList(); A != nullptr; A = A->getNext()) + if (A->getKind() == AttributeList::AT_CUDADevice || + A->getKind() == AttributeList::AT_CUDAHost || + A->getKind() == AttributeList::AT_CUDAGlobal) + Diag(A->getLoc(), diag::warn_cuda_attr_lambda_position) + << A->getName()->getName(); + }; TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { @@ -1081,13 +1109,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Scope::FunctionDeclarationScope | Scope::DeclScope); - SourceLocation DeclEndLoc; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); SourceLocation LParenLoc = T.getOpenLocation(); // Parse parameter-declaration-clause. - ParsedAttributes Attr(AttrFactory); SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; SourceLocation EllipsisLoc; @@ -1101,7 +1127,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); - DeclEndLoc = RParenLoc; + SourceLocation DeclEndLoc = RParenLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. @@ -1111,10 +1137,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // compatible with MSVC. MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); - // Parse 'mutable'[opt]. + // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc. SourceLocation MutableLoc; - if (TryConsumeToken(tok::kw_mutable, MutableLoc)) - DeclEndLoc = MutableLoc; + SourceLocation ConstexprLoc; + tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc, + DeclEndLoc); + + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; @@ -1149,6 +1178,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( PrototypeScope.Exit(); + WarnIfHasCUDATargetAttr(); + SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isAmbiguous=*/false, @@ -1169,10 +1200,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/nullptr, + /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); - } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute) || + } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, + tok::kw_constexpr) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. @@ -1182,18 +1215,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( case tok::arrow: TokKind = 1; break; case tok::kw___attribute: case tok::l_square: TokKind = 2; break; + case tok::kw_constexpr: TokKind = 3; break; default: llvm_unreachable("Unknown token kind"); } Diag(Tok, diag::err_lambda_missing_parens) << TokKind << FixItHint::CreateInsertion(Tok.getLocation(), "() "); - SourceLocation DeclLoc = Tok.getLocation(); SourceLocation DeclEndLoc = DeclLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. - ParsedAttributes Attr(AttrFactory); MaybeParseGNUAttributes(Attr, &DeclEndLoc); // Parse 'mutable', if it's there. @@ -1214,6 +1246,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = Range.getEnd(); } + WarnIfHasCUDATargetAttr(); + SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isAmbiguous=*/false, @@ -1236,11 +1270,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); } - // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. @@ -1711,6 +1745,10 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, } case ConditionOrInitStatement::InitStmtDecl: { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z + ? diag::warn_cxx14_compat_init_statement + : diag::ext_init_statement) + << (CK == Sema::ConditionKind::Switch); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy DG = ParseSimpleDeclaration( Declarator::InitStmtContext, DeclEnd, attrs, /*RequireSemi=*/true); |