diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-24 22:00:03 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-24 22:00:03 +0000 |
commit | 480093f4440d54b30b3025afeac24b48f2ba7a2e (patch) | |
tree | 162e72994062888647caf0d875428db9445491a8 /contrib/llvm-project/clang/lib/Parse | |
parent | 489b1cf2ecf5b9b4a394857987014bfb09067726 (diff) | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseAST.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp | 46 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp | 151 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp | 78 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp | 302 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp | 67 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp | 3 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp | 429 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp | 112 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseStmtAsm.cpp | 46 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp | 241 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp | 19 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/Parser.cpp | 20 |
14 files changed, 1208 insertions, 310 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp b/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp index 3efd893e499c..01510e8caf3b 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp @@ -151,7 +151,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { bool HaveLexer = S.getPreprocessor().getCurrentLexer(); if (HaveLexer) { - llvm::TimeTraceScope TimeScope("Frontend", StringRef("")); + llvm::TimeTraceScope TimeScope("Frontend"); P.Initialize(); Parser::DeclGroupPtrTy ADecl; for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; diff --git a/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp index aa314da8e5b4..f8b5fec43800 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -223,6 +223,7 @@ Parser::LateParsedDeclaration::~LateParsedDeclaration() {} void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {} void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} +void Parser::LateParsedDeclaration::ParseLexedPragmas() {} Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) : Self(P), Class(C) {} @@ -243,6 +244,10 @@ void Parser::LateParsedClass::ParseLexedMethodDefs() { Self->ParseLexedMethodDefs(*Class); } +void Parser::LateParsedClass::ParseLexedPragmas() { + Self->ParseLexedPragmas(*Class); +} + void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() { Self->ParseLexedMethodDeclaration(*this); } @@ -255,6 +260,10 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { Self->ParseLexedMemberInitializer(*this); } +void Parser::LateParsedPragma::ParseLexedPragmas() { + Self->ParseLexedPragma(*this); +} + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was @@ -651,6 +660,43 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); } +void Parser::ParseLexedPragmas(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + ++CurTemplateDepthTracker; + } + bool HasClassScope = !Class.TopLevelClass; + ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope, + HasClassScope); + + for (LateParsedDeclaration *LPD : Class.LateParsedDeclarations) + LPD->ParseLexedPragmas(); +} + +void Parser::ParseLexedPragma(LateParsedPragma &LP) { + PP.EnterToken(Tok, /*IsReinject=*/true); + PP.EnterTokenStream(LP.toks(), /*DisableMacroExpansion=*/true, + /*IsReinject=*/true); + + // Consume the previously pushed token. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + assert(Tok.isAnnotation() && "Expected annotation token."); + switch (Tok.getKind()) { + case tok::annot_pragma_openmp: { + AccessSpecifier AS = LP.getAccessSpecifier(); + ParsedAttributesWithRange Attrs(AttrFactory); + (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs); + break; + } + default: + llvm_unreachable("Unexpected token."); + } +} + /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp index b248d7582d84..69a3ed9cbad7 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp @@ -2014,6 +2014,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return nullptr; } + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + // Save late-parsed attributes for now; they need to be parsed in the // appropriate function scope after the function Decl has been constructed. // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList. @@ -2165,6 +2168,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParseDeclarator(D); if (!D.isInvalidType()) { + // C++2a [dcl.decl]p1 + // init-declarator: + // declarator initializer[opt] + // declarator requires-clause + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); D.complete(ThisDecl); if (ThisDecl) @@ -2197,7 +2206,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopBeforeMatch); return true; @@ -2349,7 +2358,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else - Diag(ConsumeToken(), diag::err_default_special_members); + Diag(ConsumeToken(), diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; } else { InitializerScopeRAII InitScope(*this, D, ThisDecl); @@ -3948,9 +3958,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec = Tok.getIdentifierInfo()->getNameStart(); isInvalid = true; break; - }; + } LLVM_FALLTHROUGH; case tok::kw_private: + // It's fine (but redundant) to check this for __generic on the + // fallthrough path; we only form the __generic token in OpenCL mode. + if (!getLangOpts().OpenCL) + goto DoneWithDeclSpec; + LLVM_FALLTHROUGH; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -5106,6 +5121,13 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { return !DisambiguatingWithExpression || !isStartOfObjCClassMessageMissingOpenBracket(); + // placeholder-type-specifier + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + return TemplateId->Kind == TNK_Concept_template && + (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); + } + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -6026,6 +6048,22 @@ void Parser::ParseDirectDeclarator(Declarator &D) { PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); + } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) { + // This declarator is declaring a function, but the requires clause is + // in the wrong place: + // void (f() requires true); + // instead of + // void f() requires true; + // or + // void (f()) requires true; + Diag(Tok, diag::err_requires_clause_inside_parens); + ConsumeToken(); + ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() && + !D.hasTrailingRequiresClause()) + // We're already ill-formed if we got here but we'll accept it anyway. + D.setTrailingRequiresClause(TrailingRequiresClause.get()); } else { break; } @@ -6206,6 +6244,47 @@ void Parser::ParseParenDeclarator(Declarator &D) { PrototypeScope.Exit(); } +void Parser::InitCXXThisScopeForDeclaratorIfRelevant( + const Declarator &D, const DeclSpec &DS, + llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + // FIXME: currently, "static" case isn't handled correctly. + bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + (D.getContext() == DeclaratorContext::MemberContext + ? !D.getDeclSpec().isFriendSpecified() + : D.getContext() == DeclaratorContext::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord()); + if (!IsCXX11MemberFunction) + return; + + Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); + if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) + Q.addConst(); + // FIXME: Collect C++ address spaces. + // If there are multiple different address spaces, the source is invalid. + // Carry on using the first addr space for the qualifiers of 'this'. + // The diagnostic will be given later while creating the function + // prototype for the method. + if (getLangOpts().OpenCLCPlusPlus) { + for (ParsedAttr &attr : DS.getAttributes()) { + LangAS ASIdx = attr.asOpenCLLangAS(); + if (ASIdx != LangAS::Default) { + Q.addAddressSpace(ASIdx); + break; + } + } + } + ThisScope.emplace(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, + IsCXX11MemberFunction); +} + /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. @@ -6219,7 +6298,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// /// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], /// (C++11) ref-qualifier[opt], exception-specification[opt], -/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt]. +/// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and +/// (C++2a) the trailing requires-clause. /// /// [C++11] exception-specification: /// dynamic-exception-specification @@ -6314,43 +6394,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or - // declarator. - // FIXME: currently, "static" case isn't handled correctly. - bool IsCXX11MemberFunction = - getLangOpts().CPlusPlus11 && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - (D.getContext() == DeclaratorContext::MemberContext - ? !D.getDeclSpec().isFriendSpecified() - : D.getContext() == DeclaratorContext::FileContext && - D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord()); - - Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); - if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) - Q.addConst(); - // FIXME: Collect C++ address spaces. - // If there are multiple different address spaces, the source is invalid. - // Carry on using the first addr space for the qualifiers of 'this'. - // The diagnostic will be given later while creating the function - // prototype for the method. - if (getLangOpts().OpenCLCPlusPlus) { - for (ParsedAttr &attr : DS.getAttributes()) { - LangAS ASIdx = attr.asOpenCLLangAS(); - if (ASIdx != LangAS::Default) { - Q.addAddressSpace(ASIdx); - break; - } - } - } - - Sema::CXXThisScopeRAII ThisScope( - Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, - IsCXX11MemberFunction); + llvm::Optional<Sema::CXXThisScopeRAII> ThisScope; + InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); // Parse exception-specification[opt]. bool Delayed = D.isFirstDeclarationOfMember() && @@ -6565,6 +6610,19 @@ void Parser::ParseParameterDeclarationClause( ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { + + // Avoid exceeding the maximum function scope depth. + // See https://bugs.llvm.org/show_bug.cgi?id=19607 + // Note Sema::ActOnParamDeclarator calls ParmVarDecl::setScopeInfo with + // getFunctionPrototypeDepth() - 1. + if (getCurScope()->getFunctionPrototypeDepth() - 1 > + ParmVarDecl::getMaxFunctionScopeDepth()) { + Diag(Tok.getLocation(), diag::err_function_scope_depth_exceeded) + << ParmVarDecl::getMaxFunctionScopeDepth(); + cutOffParsing(); + return; + } + do { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. @@ -6605,6 +6663,17 @@ void Parser::ParseParameterDeclarationClause( // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); + if (Tok.is(tok::kw_requires)) { + // User tried to define a requires clause in a parameter declaration, + // which is surely not a function declaration. + // void f(int (*g)(int, int) requires true); + Diag(Tok, + diag::err_requires_clause_on_declarator_not_declaring_a_function); + ConsumeToken(); + Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + } + // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp index b98ce3e66292..081d4d8b1209 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp @@ -600,7 +600,10 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, if (ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false, /*MayBePseudoDtor=*/nullptr, /*IsTypename=*/false, - /*LastII=*/&LastII)) + /*LastII=*/&LastII, + /*OnlyNamespace=*/false, + /*InUsingDeclaration=*/true)) + return true; if (D.SS.isInvalid()) return true; @@ -2298,6 +2301,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( LateParsedAttrList &LateParsedAttrs) { // member-declarator: // declarator pure-specifier[opt] + // declarator requires-clause // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression if (Tok.isNot(tok::colon)) @@ -2311,6 +2315,8 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + } else if (Tok.is(tok::kw_requires)) { + ParseTrailingRequiresClause(DeclaratorInfo); } else { ParseOptionalCXX11VirtSpecifierSeq( VS, getCurrentClass().IsInterface, @@ -2322,7 +2328,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); @@ -2433,6 +2439,7 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( /// /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] +/// [C++2a] declarator requires-clause /// declarator constant-initializer[opt] /// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression @@ -2666,6 +2673,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; + ExprResult TrailingRequiresClause; bool ExpectSemi = true; // Parse the first declarator. @@ -2978,7 +2986,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, Diag(Tok, diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else - Diag(ConsumeToken(), diag::err_default_special_members); + Diag(ConsumeToken(), diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; return ExprError(); } } @@ -3132,8 +3141,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( } case tok::annot_pragma_openmp: - return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType, - TagDecl); + return ParseOpenMPDeclarativeDirectiveWithExtDecl( + AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl); default: if (tok::isPragmaAnnotation(Tok.getKind())) { @@ -3351,6 +3360,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // declarations and the lexed inline method definitions, along with any // delayed attributes. SourceLocation SavedPrevTokLocation = PrevTokLocation; + ParseLexedPragmas(getCurrentClass()); ParseLexedAttributes(getCurrentClass()); ParseLexedMethodDeclarations(getCurrentClass()); @@ -3363,7 +3373,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // We've finished parsing everything, including default argument // initializers. - Actions.ActOnFinishCXXNonNestedClass(TagDecl); + Actions.ActOnFinishCXXNonNestedClass(); } if (TagDecl) @@ -3788,6 +3798,62 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range, : DeclaratorContext::TrailingReturnContext); } +/// Parse a requires-clause as part of a function declaration. +void Parser::ParseTrailingRequiresClause(Declarator &D) { + assert(Tok.is(tok::kw_requires) && "expected requires"); + + SourceLocation RequiresKWLoc = ConsumeToken(); + + ExprResult TrailingRequiresClause; + ParseScope ParamScope(this, + Scope::DeclScope | + Scope::FunctionDeclarationScope | + Scope::FunctionPrototypeScope); + + Actions.ActOnStartTrailingRequiresClause(getCurScope(), D); + + llvm::Optional<Sema::CXXThisScopeRAII> ThisScope; + InitCXXThisScopeForDeclaratorIfRelevant(D, D.getDeclSpec(), ThisScope); + + TrailingRequiresClause = + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true); + + TrailingRequiresClause = + Actions.ActOnFinishTrailingRequiresClause(TrailingRequiresClause); + + if (!D.isDeclarationOfFunction()) { + Diag(RequiresKWLoc, + diag::err_requires_clause_on_declarator_not_declaring_a_function); + return; + } + + if (TrailingRequiresClause.isInvalid()) + SkipUntil({tok::l_brace, tok::arrow, tok::kw_try, tok::comma, tok::colon}, + StopAtSemi | StopBeforeMatch); + else + D.setTrailingRequiresClause(TrailingRequiresClause.get()); + + // Did the user swap the trailing return type and requires clause? + if (D.isFunctionDeclarator() && Tok.is(tok::arrow) && + D.getDeclSpec().getTypeSpecType() == TST_auto) { + SourceLocation ArrowLoc = Tok.getLocation(); + SourceRange Range; + TypeResult TrailingReturnType = + ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit=*/false); + + if (!TrailingReturnType.isInvalid()) { + Diag(ArrowLoc, + diag::err_requires_clause_must_appear_after_trailing_return) + << Range; + auto &FunctionChunk = D.getFunctionTypeInfo(); + FunctionChunk.HasTrailingReturnType = TrailingReturnType.isUsable(); + FunctionChunk.TrailingReturnType = TrailingReturnType.get(); + } else + SkipUntil({tok::equal, tok::l_brace, tok::arrow, tok::kw_try, tok::comma}, + StopAtSemi | StopBeforeMatch); + } +} + /// We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. diff --git a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp index b74a95a3cd4b..1442df046bb9 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp @@ -22,6 +22,7 @@ #include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" @@ -145,7 +146,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { // Silence extension warnings in the sub-expression ExtensionRAIIObject O(Diags); - LHS = ParseCastExpression(false); + LHS = ParseCastExpression(AnyCastExpr); } if (!LHS.isInvalid()) @@ -169,7 +170,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::kw_co_yield)) return ParseCoyieldExpression(); - ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, + ExprResult LHS = ParseCastExpression(AnyCastExpr, /*isAddressOfOperand=*/false, isTypeCast); return ParseRHSOfBinaryExpression(LHS, prec::Assignment); @@ -202,7 +203,7 @@ Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) { Sema::ExpressionEvaluationContext::ConstantEvaluated && "Call this function only if your ExpressionEvaluationContext is " "already ConstantEvaluated"); - ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, false, isTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnConstantExpression(Res); } @@ -220,7 +221,7 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnCaseExpr(CaseLoc, Res); } @@ -234,13 +235,141 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { ExprResult Parser::ParseConstraintExpression() { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false)); + ExprResult LHS(ParseCastExpression(AnyCastExpr)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); - if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) + if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { + Actions.CorrectDelayedTyposInExpr(Res); return ExprError(); + } return Res; } +/// \brief Parse a constraint-logical-and-expression. +/// +/// \verbatim +/// C++2a[temp.constr.decl]p1 +/// constraint-logical-and-expression: +/// primary-expression +/// constraint-logical-and-expression '&&' primary-expression +/// +/// \endverbatim +ExprResult +Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + bool NotPrimaryExpression = false; + auto ParsePrimary = [&] () { + ExprResult E = ParseCastExpression(PrimaryExprOnly, + /*isAddressOfOperand=*/false, + /*isTypeCast=*/NotTypeCast, + /*isVectorLiteral=*/false, + &NotPrimaryExpression); + if (E.isInvalid()) + return ExprError(); + auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) { + E = ParsePostfixExpressionSuffix(E); + // Use InclusiveOr, the precedence just after '&&' to not parse the + // next arguments to the logical and. + E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr); + if (!E.isInvalid()) + Diag(E.get()->getExprLoc(), + Note + ? diag::note_unparenthesized_non_primary_expr_in_requires_clause + : diag::err_unparenthesized_non_primary_expr_in_requires_clause) + << FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(") + << FixItHint::CreateInsertion( + PP.getLocForEndOfToken(E.get()->getEndLoc()), ")") + << E.get()->getSourceRange(); + return E; + }; + + if (NotPrimaryExpression || + // Check if the following tokens must be a part of a non-primary + // expression + getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, + /*CPlusPlus11=*/true) > prec::LogicalAnd || + // Postfix operators other than '(' (which will be checked for in + // CheckConstraintExpression). + Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) || + (Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) { + E = RecoverFromNonPrimary(E, /*Note=*/false); + if (E.isInvalid()) + return ExprError(); + NotPrimaryExpression = false; + } + bool PossibleNonPrimary; + bool IsConstraintExpr = + Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary, + IsTrailingRequiresClause); + if (!IsConstraintExpr || PossibleNonPrimary) { + // Atomic constraint might be an unparenthesized non-primary expression + // (such as a binary operator), in which case we might get here (e.g. in + // 'requires 0 + 1 && true' we would now be at '+', and parse and ignore + // the rest of the addition expression). Try to parse the rest of it here. + if (PossibleNonPrimary) + E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr); + Actions.CorrectDelayedTyposInExpr(E); + return ExprError(); + } + return E; + }; + ExprResult LHS = ParsePrimary(); + if (LHS.isInvalid()) + return ExprError(); + while (Tok.is(tok::ampamp)) { + SourceLocation LogicalAndLoc = ConsumeToken(); + ExprResult RHS = ParsePrimary(); + if (RHS.isInvalid()) { + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc, + tok::ampamp, LHS.get(), RHS.get()); + if (!Op.isUsable()) { + Actions.CorrectDelayedTyposInExpr(RHS); + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + LHS = Op; + } + return LHS; +} + +/// \brief Parse a constraint-logical-or-expression. +/// +/// \verbatim +/// C++2a[temp.constr.decl]p1 +/// constraint-logical-or-expression: +/// constraint-logical-and-expression +/// constraint-logical-or-expression '||' +/// constraint-logical-and-expression +/// +/// \endverbatim +ExprResult +Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) { + ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause)); + if (!LHS.isUsable()) + return ExprError(); + while (Tok.is(tok::pipepipe)) { + SourceLocation LogicalOrLoc = ConsumeToken(); + ExprResult RHS = + ParseConstraintLogicalAndExpression(IsTrailingRequiresClause); + if (!RHS.isUsable()) { + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc, + tok::pipepipe, LHS.get(), RHS.get()); + if (!Op.isUsable()) { + Actions.CorrectDelayedTyposInExpr(RHS); + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + LHS = Op; + } + return LHS; +} + bool Parser::isNotExpressionStart() { tok::TokenKind K = Tok.getKind(); if (K == tok::l_brace || K == tok::r_brace || @@ -414,7 +543,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else - RHS = ParseCastExpression(false); + RHS = ParseCastExpression(AnyCastExpr); if (RHS.isInvalid()) { // FIXME: Errors generated by the delayed typo correction should be @@ -519,22 +648,24 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } -/// Parse a cast-expression, or, if \p isUnaryExpression is true, -/// parse a unary-expression. +/// Parse a cast-expression, unary-expression or primary-expression, based +/// on \p ExprType. /// /// \p isAddressOfOperand exists because an id-expression that is the /// operand of address-of gets special treatment due to member pointers. /// -ExprResult Parser::ParseCastExpression(bool isUnaryExpression, +ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, TypeCastState isTypeCast, - bool isVectorLiteral) { + bool isVectorLiteral, + bool *NotPrimaryExpression) { bool NotCastExpr; - ExprResult Res = ParseCastExpression(isUnaryExpression, + ExprResult Res = ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, - isVectorLiteral); + isVectorLiteral, + NotPrimaryExpression); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return Res; @@ -759,11 +890,12 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback { /// '__is_rvalue_expr' /// \endverbatim /// -ExprResult Parser::ParseCastExpression(bool isUnaryExpression, +ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, bool &NotCastExpr, TypeCastState isTypeCast, - bool isVectorLiteral) { + bool isVectorLiteral, + bool *NotPrimaryExpression) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); auto SavedType = PreferredType; @@ -782,11 +914,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { - // If this expression is limited to being a unary-expression, the parent can + // If this expression is limited to being a unary-expression, the paren can // not start a cast expression. - ParenParseOption ParenExprType = - (isUnaryExpression && !getLangOpts().CPlusPlus) ? CompoundLiteral - : CastExpr; + ParenParseOption ParenExprType; + switch (ParseKind) { + case CastParseKind::UnaryExprOnly: + if (!getLangOpts().CPlusPlus) + ParenExprType = CompoundLiteral; + LLVM_FALLTHROUGH; + case CastParseKind::AnyCastExpr: + ParenExprType = ParenParseOption::CastExpr; + break; + case CastParseKind::PrimaryExprOnly: + ParenExprType = FoldExpr; + break; + } ParsedType CastTy; SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, @@ -861,8 +1003,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); - + return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, + isVectorLiteral, NotPrimaryExpression); + case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant @@ -949,8 +1092,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, = RevertibleTypeTraits.find(II); if (Known != RevertibleTypeTraits.end()) { Tok.setKind(Known->second); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, + isVectorLiteral, NotPrimaryExpression); } } @@ -961,7 +1105,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::identifier)) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, + isVectorLiteral, + NotPrimaryExpression); } } @@ -1076,8 +1223,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Tok.is(tok::r_paren) ? nullptr : &Replacement); if (!Res.isInvalid() && Res.isUnset()) { UnconsumeToken(Replacement); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, + /*isVectorLiteral=*/false, + NotPrimaryExpression); } if (!Res.isInvalid() && Tok.is(tok::less)) checkPotentialAngleBracket(Res); @@ -1122,12 +1271,16 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_FILE: case tok::kw___builtin_FUNCTION: case tok::kw___builtin_LINE: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); case tok::plusplus: // unary-expression: '++' unary-expression [C99] case tok::minusminus: { // unary-expression: '--' unary-expression [C99] + if (NotPrimaryExpression) + *NotPrimaryExpression = true; // C++ [expr.unary] has: // unary-expression: // ++ cast-expression @@ -1140,7 +1293,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. - Res = ParseCastExpression(!getLangOpts().CPlusPlus, + Res = ParseCastExpression(getLangOpts().CPlusPlus ? + UnaryExprOnly : AnyCastExpr, /*isAddressOfOperand*/false, NotCastExpr, NotTypeCast); if (NotCastExpr) { @@ -1156,10 +1310,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return Res; } case tok::amp: { // unary-expression: '&' cast-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc); - Res = ParseCastExpression(false, true); + Res = ParseCastExpression(AnyCastExpr, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; @@ -1172,17 +1328,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::exclaim: // unary-expression: '!' cast-expression case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation SavedLoc = ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc); - Res = ParseCastExpression(false); + Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; } case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation CoawaitLoc = ConsumeToken(); - Res = ParseCastExpression(false); + Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get()); return Res; @@ -1190,9 +1350,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // __extension__ silences extension warnings in the subexpression. + if (NotPrimaryExpression) + *NotPrimaryExpression = true; ExtensionRAIIObject O(Diags); // Use RAII to do this. SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false); + Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; @@ -1209,8 +1371,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')' case tok::kw___builtin_omp_required_simd_align: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); @@ -1229,15 +1395,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_dynamic_cast: case tok::kw_reinterpret_cast: case tok::kw_static_cast: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseCXXCasts(); break; case tok::kw___builtin_bit_cast: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseBuiltinBitCast(); break; case tok::kw_typeid: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseCXXTypeid(); break; case tok::kw___uuidof: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseCXXUuidof(); break; case tok::kw_this: @@ -1302,6 +1476,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ExprError(); } + // Everything henceforth is a postfix-expression. + if (NotPrimaryExpression) + *NotPrimaryExpression = true; + if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' // typename-specifier braced-init-list @@ -1338,8 +1516,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::annot_cxxscope)) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression); Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { @@ -1352,8 +1531,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression); } } @@ -1369,8 +1549,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // translate it into a type and continue parsing as a cast // expression. AnnotateTemplateIdTokenAsType(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, isVectorLiteral, + NotPrimaryExpression); } // Fall through to treat the template-id as an id-expression. @@ -1387,15 +1568,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::coloncolon)) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, + isVectorLiteral, NotPrimaryExpression); // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression SourceLocation CCLoc = ConsumeToken(); - if (Tok.is(tok::kw_new)) + if (Tok.is(tok::kw_new)) { + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXNewExpression(true, CCLoc); - if (Tok.is(tok::kw_delete)) + } + if (Tok.is(tok::kw_delete)) { + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXDeleteExpression(true, CCLoc); + } // This is not a type name or scope specifier, it is an invalid expression. Diag(CCLoc, diag::err_expected_expression); @@ -1403,12 +1591,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::kw_new: // [C++] new-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXNewExpression(false, Tok.getLocation()); case tok::kw_delete: // [C++] delete-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXDeleteExpression(false, Tok.getLocation()); case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); SourceLocation KeyLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); @@ -1437,13 +1631,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___array_rank: case tok::kw___array_extent: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseArrayTypeTrait(); case tok::kw___is_lvalue_expr: case tok::kw___is_rvalue_expr: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseExpressionTrait(); case tok::at: { + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); } @@ -1465,8 +1665,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // expression, or we have something that doesn't appear to be a lambda. // If we're in the last case, we fall back to ParseObjCMessageExpression. Res = TryParseLambdaExpression(); - if (!Res.isInvalid() && !Res.get()) + if (!Res.isInvalid() && !Res.get()) { + // We assume Objective-C++ message expressions are not + // primary-expressions. + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseObjCMessageExpression(); + } break; } Res = ParseLambdaExpression(); @@ -1486,6 +1691,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // are compiling for OpenCL, we need to return an error as this implies // that the address of the function is being taken, which is illegal in CL. + if (ParseKind == PrimaryExprOnly) + // This is strictly a primary-expression - no postfix-expr pieces should be + // parsed. + return Res; + // These can be followed by postfix-expr pieces. PreferredType = SavedType; Res = ParsePostfixExpressionSuffix(Res); @@ -1929,7 +2139,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return ExprError(); } - Operand = ParseCastExpression(true/*isUnaryExpression*/); + Operand = ParseCastExpression(UnaryExprOnly); } else { // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound @@ -2474,8 +2684,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, RParenLoc = T.getCloseLocation(); PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get()); - ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); - + ExprResult SubExpr = ParseCastExpression(AnyCastExpr); + if (Ty.isInvalid() || SubExpr.isInvalid()) return ExprError(); @@ -2555,7 +2765,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the cast-expression that follows it next. // isVectorLiteral = true will make sure we don't parse any // Postfix expression yet - Result = ParseCastExpression(/*isUnaryExpression=*/false, + Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast, /*isVectorLiteral=*/true); @@ -2607,7 +2817,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get()); // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. - Result = ParseCastExpression(/*isUnaryExpression=*/false, + Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast); if (!Result.isInvalid()) { diff --git a/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp index a064e4b17587..e685d5ea8a9c 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp @@ -142,6 +142,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /// /// \param OnlyNamespace If true, only considers namespaces in lookup. /// +/// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, @@ -149,7 +150,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, bool *MayBePseudoDestructor, bool IsTypename, IdentifierInfo **LastII, - bool OnlyNamespace) { + bool OnlyNamespace, + bool InUsingDeclaration) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -240,7 +242,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Code completion for a nested-name-specifier, where the code // completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext, - ObjectType.get(), + InUsingDeclaration, ObjectType.get(), SavedType.get(SS.getBeginLoc())); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion @@ -479,6 +481,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // nested-name-specifier: // type-name '<' if (Next.is(tok::less)) { + TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); @@ -503,7 +506,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // template-id to be translated into a type annotation, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id - // token. + // token, and it might not be a type at all (e.g. a concept name in a + // type-constraint). ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) @@ -1355,6 +1359,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // Parse attribute-specifier[opt]. MaybeParseCXX11Attributes(Attr, &DeclEndLoc); + // Parse OpenCL addr space attribute. + if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic)) { + ParseOpenCLQualifiers(DS.getAttributes()); + ConsumeToken(); + } + SourceLocation FunLocalRangeEnd = DeclEndLoc; // Parse trailing-return-type[opt]. @@ -1367,10 +1378,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = Range.getEnd(); } - PrototypeScope.Exit(); - - WarnIfHasCUDATargetAttr(); - SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction( /*HasProto=*/true, @@ -1383,21 +1390,38 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/ nullptr, /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, - TrailingReturnType), + TrailingReturnType, &DS), std::move(Attr), DeclEndLoc); + + // Parse requires-clause[opt]. + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + + PrototypeScope.Exit(); + + WarnIfHasCUDATargetAttr(); } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, - tok::kw_constexpr, tok::kw_consteval) || + tok::kw_constexpr, tok::kw_consteval, + tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic, + tok::kw_requires) || (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. + // specifier, the result type, or the requires clause. Deal with this. unsigned TokKind = 0; switch (Tok.getKind()) { case tok::kw_mutable: TokKind = 0; break; case tok::arrow: TokKind = 1; break; case tok::kw___attribute: + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___generic: case tok::l_square: TokKind = 2; break; case tok::kw_constexpr: TokKind = 3; break; case tok::kw_consteval: TokKind = 4; break; + case tok::kw_requires: TokKind = 5; break; default: llvm_unreachable("Unknown token kind"); } @@ -1429,8 +1453,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = Range.getEnd(); } - WarnIfHasCUDATargetAttr(); - SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction( /*HasProto=*/true, @@ -1451,6 +1473,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, TrailingReturnType), std::move(Attr), DeclEndLoc); + + // Parse the requires-clause, if present. + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + + WarnIfHasCUDATargetAttr(); } // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using @@ -1851,9 +1879,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { CommaLocsTy CommaLocs; auto RunSignatureHelp = [&]() { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); + QualType PreferredType; + if (TypeRep) + PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DS.getEndLoc(), Exprs, T.getOpenLocation()); CalledSignatureHelp = true; return PreferredType; }; @@ -2004,7 +2034,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, // simple-asm-expr[opt] if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopAtSemi); return Sema::ConditionError(); @@ -3027,6 +3057,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { auto RunSignatureHelp = [&]() { ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + assert(TypeRep && "invalid types should be handled before"); QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); @@ -3224,7 +3255,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { return ExprError(); } - ExprResult Operand(ParseCastExpression(false)); + ExprResult Operand(ParseCastExpression(AnyCastExpr)); if (Operand.isInvalid()) return Operand; @@ -3455,7 +3486,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // If it is not a cast-expression, NotCastExpr will be true and no token // will be consumed. ColonProt.restore(); - Result = ParseCastExpression(false/*isUnaryExpression*/, + Result = ParseCastExpression(AnyCastExpr, false/*isAddressofOperand*/, NotCastExpr, // type-id has priority. diff --git a/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp index 42d6221a7333..efcef6d3b123 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp @@ -822,6 +822,7 @@ static void diagnoseRedundantPropertyNullability(Parser &P, /// property-attribute: /// getter '=' identifier /// setter '=' identifier ':' +/// direct /// readonly /// readwrite /// assign @@ -954,6 +955,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable); } else if (II->isStr("class")) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class); + } else if (II->isStr("direct")) { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_direct); } else { Diag(AttrName, diag::err_objc_expected_property_attr) << II; SkipUntil(tok::r_paren, StopAtSemi); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp index 91fe10e667db..1095919baa7d 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -20,6 +21,7 @@ #include "llvm/ADT/UniqueVector.h" using namespace clang; +using namespace llvm::omp; //===----------------------------------------------------------------------===// // OpenMP declarative directives. @@ -27,7 +29,7 @@ using namespace clang; namespace { enum OpenMPDirectiveKindEx { - OMPD_cancellation = OMPD_unknown + 1, + OMPD_cancellation = unsigned(OMPD_unknown) + 1, OMPD_data, OMPD_declare, OMPD_end, @@ -44,7 +46,20 @@ enum OpenMPDirectiveKindEx { OMPD_target_teams_distribute_parallel, OMPD_mapper, OMPD_variant, - OMPD_parallel_master, +}; + +// Helper to unify the enum class OpenMPDirectiveKind with its extension +// the OpenMPDirectiveKindEx enum which allows to use them together as if they +// are unsigned values. +struct OpenMPDirectiveKindExWrapper { + OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {} + OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {} + bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); } + bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); } + bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); } + operator unsigned() const { return Value; } + operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); } + unsigned Value; }; class DeclDirectiveListParserHelper final { @@ -68,11 +83,11 @@ public: // Map token string to extended OMP token kind that are // OpenMPDirectiveKind + OpenMPDirectiveKindEx. static unsigned getOpenMPDirectiveKindEx(StringRef S) { - auto DKind = getOpenMPDirectiveKind(S); + OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S); if (DKind != OMPD_unknown) return DKind; - return llvm::StringSwitch<unsigned>(S) + return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S) .Case("cancellation", OMPD_cancellation) .Case("data", OMPD_data) .Case("declare", OMPD_declare) @@ -87,11 +102,11 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) { .Default(OMPD_unknown); } -static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { +static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { // Array of foldings: F[i][0] F[i][1] ===> F[i][2]. // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. - static const unsigned F[][3] = { + static const OpenMPDirectiveKindExWrapper F[][3] = { {OMPD_cancellation, OMPD_point, OMPD_cancellation_point}, {OMPD_declare, OMPD_reduction, OMPD_declare_reduction}, {OMPD_declare, OMPD_mapper, OMPD_declare_mapper}, @@ -140,10 +155,12 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { {OMPD_master, OMPD_taskloop, OMPD_master_taskloop}, {OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd}, {OMPD_parallel, OMPD_master, OMPD_parallel_master}, - {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop}}; + {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop}, + {OMPD_parallel_master_taskloop, OMPD_simd, + OMPD_parallel_master_taskloop_simd}}; enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 }; Token Tok = P.getCurToken(); - unsigned DKind = + OpenMPDirectiveKindExWrapper DKind = Tok.isAnnotation() ? static_cast<unsigned>(OMPD_unknown) : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); @@ -155,7 +172,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { continue; Tok = P.getPreprocessor().LookAhead(0); - unsigned SDKind = + OpenMPDirectiveKindExWrapper SDKind = Tok.isAnnotation() ? static_cast<unsigned>(OMPD_unknown) : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); @@ -237,8 +254,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(OMPD_declare_reduction))) { + if (T.expectAndConsume( + diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_reduction).data())) { SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); return DeclGroupPtrTy(); } @@ -325,9 +343,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { Scope::OpenMPDirectiveScope); // Parse <combiner> expression. Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); - ExprResult CombinerResult = - Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(), - D->getLocation(), /*DiscardedValue*/ false); + ExprResult CombinerResult = Actions.ActOnFinishFullExpr( + ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false); Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get()); if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) && @@ -366,14 +383,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { // Check if initializer is omp_priv <init_expr> or something else. if (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("omp_priv")) { - if (Actions.getLangOpts().CPlusPlus) { - InitializerResult = Actions.ActOnFinishFullExpr( - ParseAssignmentExpression().get(), D->getLocation(), - /*DiscardedValue*/ false); - } else { - ConsumeToken(); - ParseOpenMPReductionInitializerForDecl(OmpPrivParm); - } + ConsumeToken(); + ParseOpenMPReductionInitializerForDecl(OmpPrivParm); } else { InitializerResult = Actions.ActOnFinishFullExpr( ParseAssignmentExpression().get(), D->getLocation(), @@ -417,7 +428,8 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { return; } - ExprResult Init(ParseInitializer()); + PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm); + ExprResult Init = ParseInitializer(); if (Init.isInvalid()) { SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -495,7 +507,7 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { // Parse '(' BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(OMPD_declare_mapper))) { + getOpenMPDirectiveName(OMPD_declare_mapper).data())) { SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); return DeclGroupPtrTy(); } @@ -722,10 +734,12 @@ static bool parseDeclareSimdClauses( CKind == OMPC_linear) { Parser::OpenMPVarListDataTy Data; SmallVectorImpl<Expr *> *Vars = &Uniforms; - if (CKind == OMPC_aligned) + if (CKind == OMPC_aligned) { Vars = &Aligneds; - else if (CKind == OMPC_linear) + } else if (CKind == OMPC_linear) { + Data.ExtraModifier = OMPC_LINEAR_val; Vars = &Linears; + } P.ConsumeToken(); if (P.ParseOpenMPVarList(OMPD_declare_simd, @@ -734,11 +748,15 @@ static bool parseDeclareSimdClauses( if (CKind == OMPC_aligned) { Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr); } else if (CKind == OMPC_linear) { - if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind, - Data.DepLinMapLoc)) - Data.LinKind = OMPC_LINEAR_val; + assert(0 <= Data.ExtraModifier && + Data.ExtraModifier <= OMPC_LINEAR_unknown && + "Unexpected linear modifier."); + if (P.getActions().CheckOpenMPLinearModifier( + static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier), + Data.DepLinMapLastLoc)) + Data.ExtraModifier = OMPC_LINEAR_val; LinModifiers.append(Linears.size() - LinModifiers.size(), - Data.LinKind); + Data.ExtraModifier); Steps.append(Linears.size() - Steps.size(), Data.TailExpr); } } else @@ -795,16 +813,11 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, /// Parse optional 'score' '(' <expr> ')' ':'. static ExprResult parseContextScore(Parser &P) { ExprResult ScoreExpr; - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef SelectorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); - OMPDeclareVariantAttr::ScoreType ScoreKind = - OMPDeclareVariantAttr::ScoreUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToScoreType(SelectorName, ScoreKind); - if (ScoreKind == OMPDeclareVariantAttr::ScoreUnknown) + if (!SelectorName.equals("score")) return ScoreExpr; - assert(ScoreKind == OMPDeclareVariantAttr::ScoreSpecified && - "Expected \"score\" clause."); (void)P.ConsumeToken(); SourceLocation RLoc; ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc); @@ -820,11 +833,10 @@ static ExprResult parseContextScore(Parser &P) { /// Parse context selector for 'implementation' selector set: /// 'vendor' '(' [ 'score' '(' <score _expr> ')' ':' ] <vendor> { ',' <vendor> } /// ')' -static void parseImplementationSelector( - Parser &P, SourceLocation Loc, llvm::StringMap<SourceLocation> &UsedCtx, - llvm::function_ref<void(SourceRange, - const Sema::OpenMPDeclareVariantCtsSelectorData &)> - Callback) { +static void +parseImplementationSelector(Parser &P, SourceLocation Loc, + llvm::StringMap<SourceLocation> &UsedCtx, + SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { const Token &Tok = P.getCurToken(); // Parse inner context selector set name, if any. if (!Tok.is(tok::identifier)) { @@ -836,7 +848,7 @@ static void parseImplementationSelector( ; return; } - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); if (!Res.second) { @@ -847,19 +859,16 @@ static void parseImplementationSelector( P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) << CtxSelectorName; } - OMPDeclareVariantAttr::CtxSelectorType CSKind = - OMPDeclareVariantAttr::CtxUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName, - CSKind); + OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); (void)P.ConsumeToken(); switch (CSKind) { - case OMPDeclareVariantAttr::CtxVendor: { + case OMP_CTX_vendor: { // Parse '('. BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); (void)T.expectAndConsume(diag::err_expected_lparen_after, CtxSelectorName.data()); - const ExprResult Score = parseContextScore(P); - llvm::UniqueVector<llvm::SmallString<16>> Vendors; + ExprResult Score = parseContextScore(P); + llvm::UniqueVector<Sema::OMPCtxStringType> Vendors; do { // Parse <vendor>. StringRef VendorName; @@ -882,18 +891,12 @@ static void parseImplementationSelector( } while (Tok.is(tok::identifier)); // Parse ')'. (void)T.consumeClose(); - if (!Vendors.empty()) { - SmallVector<StringRef, 4> ImplVendors(Vendors.size()); - llvm::copy(Vendors, ImplVendors.begin()); - Sema::OpenMPDeclareVariantCtsSelectorData Data( - OMPDeclareVariantAttr::CtxSetImplementation, CSKind, - llvm::makeMutableArrayRef(ImplVendors.begin(), ImplVendors.size()), - Score); - Callback(SourceRange(Loc, Tok.getLocation()), Data); - } + if (!Vendors.empty()) + Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors); break; } - case OMPDeclareVariantAttr::CtxUnknown: + case OMP_CTX_kind: + case OMP_CTX_unknown: P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) << "implementation"; // Skip until either '}', ')', or end of directive. @@ -904,15 +907,97 @@ static void parseImplementationSelector( } } +/// Parse context selector for 'device' selector set: +/// 'kind' '(' <kind> { ',' <kind> } ')' +static void +parseDeviceSelector(Parser &P, SourceLocation Loc, + llvm::StringMap<SourceLocation> &UsedCtx, + SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { + const Token &Tok = P.getCurToken(); + // Parse inner context selector set name, if any. + if (!Tok.is(tok::identifier)) { + P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) + << "device"; + // Skip until either '}', ')', or end of directive. + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return; + } + Sema::OMPCtxStringType Buffer; + StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); + auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); + if (!Res.second) { + // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. + // Each trait-selector-name can only be specified once. + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use) + << CtxSelectorName << "device"; + P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) + << CtxSelectorName; + } + OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); + (void)P.ConsumeToken(); + switch (CSKind) { + case OMP_CTX_kind: { + // Parse '('. + BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); + (void)T.expectAndConsume(diag::err_expected_lparen_after, + CtxSelectorName.data()); + llvm::UniqueVector<Sema::OMPCtxStringType> Kinds; + do { + // Parse <kind>. + StringRef KindName; + if (Tok.is(tok::identifier)) { + Buffer.clear(); + KindName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); + SourceLocation SLoc = P.getCurToken().getLocation(); + (void)P.ConsumeToken(); + if (llvm::StringSwitch<bool>(KindName) + .Case("host", false) + .Case("nohost", false) + .Case("cpu", false) + .Case("gpu", false) + .Case("fpga", false) + .Default(true)) { + P.Diag(SLoc, diag::err_omp_wrong_device_kind_trait) << KindName; + } else { + Kinds.insert(KindName); + } + } else { + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected) + << "'host', 'nohost', 'cpu', 'gpu', or 'fpga'" + << "kind" + << "device"; + } + if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) { + P.Diag(Tok, diag::err_expected_punc) + << (KindName.empty() ? "kind of device" : KindName); + } + } while (Tok.is(tok::identifier)); + // Parse ')'. + (void)T.consumeClose(); + if (!Kinds.empty()) + Data.emplace_back(OMP_CTX_SET_device, CSKind, ExprResult(), Kinds); + break; + } + case OMP_CTX_vendor: + case OMP_CTX_unknown: + P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) + << "device"; + // Skip until either '}', ')', or end of directive. + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return; + } +} + /// Parses clauses for 'declare variant' directive. /// clause: /// <selector_set_name> '=' '{' <context_selectors> '}' /// [ ',' <selector_set_name> '=' '{' <context_selectors> '}' ] bool Parser::parseOpenMPContextSelectors( - SourceLocation Loc, - llvm::function_ref<void(SourceRange, - const Sema::OpenMPDeclareVariantCtsSelectorData &)> - Callback) { + SourceLocation Loc, SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { llvm::StringMap<SourceLocation> UsedCtxSets; do { // Parse inner context selector set name. @@ -921,7 +1006,7 @@ bool Parser::parseOpenMPContextSelectors( << getOpenMPClauseName(OMPC_match); return true; } - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef CtxSelectorSetName = PP.getSpelling(Tok, Buffer); auto Res = UsedCtxSets.try_emplace(CtxSelectorSetName, Tok.getLocation()); if (!Res.second) { @@ -949,17 +1034,18 @@ bool Parser::parseOpenMPContextSelectors( tok::annot_pragma_openmp_end); if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "=")) return true; - OMPDeclareVariantAttr::CtxSelectorSetType CSSKind = - OMPDeclareVariantAttr::CtxSetUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType( - CtxSelectorSetName, CSSKind); + OpenMPContextSelectorSetKind CSSKind = + getOpenMPContextSelectorSet(CtxSelectorSetName); llvm::StringMap<SourceLocation> UsedCtx; do { switch (CSSKind) { - case OMPDeclareVariantAttr::CtxSetImplementation: - parseImplementationSelector(*this, Loc, UsedCtx, Callback); + case OMP_CTX_SET_implementation: + parseImplementationSelector(*this, Loc, UsedCtx, Data); break; - case OMPDeclareVariantAttr::CtxSetUnknown: + case OMP_CTX_SET_device: + parseDeviceSelector(*this, Loc, UsedCtx, Data); + break; + case OMP_CTX_SET_unknown: // Skip until either '}', ')', or end of directive. while (!SkipUntil(tok::r_brace, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch)) @@ -998,9 +1084,16 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, SourceLocation RLoc; // Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs // instead of MemberExprs. - ExprResult AssociatedFunction = - ParseOpenMPParensExpr(getOpenMPDirectiveName(OMPD_declare_variant), RLoc, - /*IsAddressOfOperand=*/true); + ExprResult AssociatedFunction; + { + // Do not mark function as is used to prevent its emission if this is the + // only place where it is used. + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::Unevaluated); + AssociatedFunction = ParseOpenMPParensExpr( + getOpenMPDirectiveName(OMPD_declare_variant), RLoc, + /*IsAddressOfOperand=*/true); + } if (!AssociatedFunction.isUsable()) { if (!Tok.is(tok::annot_pragma_openmp_end)) while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) @@ -1039,15 +1132,8 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, } // Parse inner context selectors. - if (!parseOpenMPContextSelectors( - Loc, [this, &DeclVarData]( - SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { - if (DeclVarData.hasValue()) - Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData.getValue().first, DeclVarData.getValue().second, - SR, Data); - })) { + SmallVector<Sema::OMPCtxSelectorData, 4> Data; + if (!parseOpenMPContextSelectors(Loc, Data)) { // Parse ')'. (void)T.consumeClose(); // Need to check for extra tokens. @@ -1060,6 +1146,10 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, // Skip last tokens. while (Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); + if (DeclVarData.hasValue()) + Actions.ActOnOpenMPDeclareVariantDirective( + DeclVarData.getValue().first, DeclVarData.getValue().second, + SourceRange(Loc, Tok.getLocation()), Data); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); } @@ -1245,13 +1335,45 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, /// annot_pragma_openmp_end /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( - AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, + AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed, DeclSpec::TST TagType, Decl *Tag) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SourceLocation Loc = ConsumeAnnotationToken(); - OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); + SourceLocation Loc; + OpenMPDirectiveKind DKind; + if (Delayed) { + TentativeParsingAction TPA(*this); + Loc = ConsumeAnnotationToken(); + DKind = parseOpenMPDirectiveKind(*this); + if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) { + // Need to delay parsing until completion of the parent class. + TPA.Revert(); + CachedTokens Toks; + unsigned Cnt = 1; + Toks.push_back(Tok); + while (Cnt && Tok.isNot(tok::eof)) { + (void)ConsumeAnyToken(); + if (Tok.is(tok::annot_pragma_openmp)) + ++Cnt; + else if (Tok.is(tok::annot_pragma_openmp_end)) + --Cnt; + Toks.push_back(Tok); + } + // Skip last annot_pragma_openmp_end. + if (Cnt == 0) + (void)ConsumeAnyToken(); + auto *LP = new LateParsedPragma(this, AS); + LP->takeToks(Toks); + getCurrentClass().LateParsedDeclarations.push_back(LP); + return nullptr; + } + TPA.Commit(); + } else { + Loc = ConsumeAnnotationToken(); + DKind = parseOpenMPDirectiveKind(*this); + } switch (DKind) { case OMPD_threadprivate: { @@ -1403,7 +1525,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( DeclGroupPtrTy Ptr; if (Tok.is(tok::annot_pragma_openmp)) { - Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag); + Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed, + TagType, Tag); } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Here we expect to see some function declaration. if (AS == AS_none) { @@ -1496,6 +1619,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: + case OMPD_parallel_master: case OMPD_atomic: case OMPD_target: case OMPD_teams: @@ -1511,6 +1635,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_distribute: case OMPD_end_declare_target: case OMPD_target_update: @@ -1562,24 +1687,26 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | -/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' | -/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' | -/// 'for simd' | 'parallel for simd' | 'target' | 'target data' | -/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | 'master -/// taskloop' | 'master taskloop simd' | 'parallel master taskloop' | -/// 'distribute' | 'target enter data' | 'target exit data' | 'target -/// parallel' | 'target parallel for' | 'target update' | 'distribute -/// parallel for' | 'distribute paralle for simd' | 'distribute simd' | -/// 'target parallel for simd' | 'target simd' | 'teams distribute' | -/// 'teams distribute simd' | 'teams distribute parallel for simd' | -/// 'teams distribute parallel for' | 'target teams' | 'target teams -/// distribute' | 'target teams distribute parallel for' | 'target teams -/// distribute parallel for simd' | 'target teams distribute simd' -/// {clause} annot_pragma_openmp_end +/// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' | +/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | +/// 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target +/// data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | +/// 'master taskloop' | 'master taskloop simd' | 'parallel master +/// taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target +/// enter data' | 'target exit data' | 'target parallel' | 'target +/// parallel for' | 'target update' | 'distribute parallel for' | +/// 'distribute paralle for simd' | 'distribute simd' | 'target parallel +/// for simd' | 'target simd' | 'teams distribute' | 'teams distribute +/// simd' | 'teams distribute parallel for simd' | 'teams distribute +/// parallel for' | 'target teams' | 'target teams distribute' | 'target +/// teams distribute parallel for' | 'target teams distribute parallel +/// for simd' | 'target teams distribute simd' {clause} +/// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector<OMPClause *, 5> Clauses; SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> @@ -1739,6 +1866,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: + case OMPD_parallel_master: case OMPD_task: case OMPD_ordered: case OMPD_atomic: @@ -1753,6 +1881,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_distribute: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: @@ -1890,7 +2019,7 @@ bool Parser::ParseOpenMPSimpleVarList( // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) + getOpenMPDirectiveName(Kind).data())) return true; bool IsCorrect = true; bool NoIdentIsFound = true; @@ -1963,7 +2092,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, bool ErrorFound = false; bool WrongDirective = false; // Check if clause is allowed for the given directive. - if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { + if (CKind != OMPC_unknown && + !isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) { Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); ErrorFound = true; @@ -2042,15 +2172,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_defaultmap: // OpenMP [2.7.1, Restrictions, p. 3] // Only one schedule clause can appear on a loop directive. - // OpenMP [2.10.4, Restrictions, p. 106] + // OpenMP 4.5 [2.10.4, Restrictions, p. 106] // At most one defaultmap clause can appear on the directive. - if (!FirstClause) { + if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) && + !FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; ErrorFound = true; } LLVM_FALLTHROUGH; - case OMPC_if: Clause = ParseOpenMPSingleExprWithArgClause(CKind, WrongDirective); break; @@ -2102,6 +2232,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_use_device_ptr: case OMPC_is_device_ptr: case OMPC_allocate: + case OMPC_nontemporal: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_device_type: @@ -2133,8 +2264,8 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, return ExprError(); SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression( - /*isUnaryExpression=*/false, IsAddressOfOperand, NotTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, IsAddressOfOperand, + NotTypeCast)); ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); @@ -2334,8 +2465,13 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind, DelimLoc = ConsumeAnyToken(); } else if (Kind == OMPC_defaultmap) { // Get a defaultmap modifier - Arg.push_back(getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + unsigned Modifier = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); + // Set defaultmap modifier to unknown if it is either scalar, aggregate, or + // pointer + if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown) + Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown; + Arg.push_back(Modifier); KLoc.push_back(Tok.getLocation()); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) @@ -2356,15 +2492,16 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind, assert(Kind == OMPC_if); KLoc.push_back(Tok.getLocation()); TentativeParsingAction TPA(*this); - Arg.push_back(parseOpenMPDirectiveKind(*this)); - if (Arg.back() != OMPD_unknown) { + auto DK = parseOpenMPDirectiveKind(*this); + Arg.push_back(DK); + if (DK != OMPD_unknown) { ConsumeToken(); if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) { TPA.Commit(); DelimLoc = ConsumeToken(); } else { TPA.Revert(); - Arg.back() = OMPD_unknown; + Arg.back() = unsigned(OMPD_unknown); } } else { TPA.Revert(); @@ -2376,7 +2513,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind, Kind == OMPC_if; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast)); Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); @@ -2541,8 +2678,8 @@ static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { P.Diag(Tok, diag::err_omp_map_type_missing); return; } - Data.MapType = isMapType(P); - if (Data.MapType == OMPC_MAP_unknown) + Data.ExtraModifier = isMapType(P); + if (Data.ExtraModifier == OMPC_MAP_unknown) P.Diag(Tok, diag::err_omp_unknown_map_type); P.ConsumeToken(); } @@ -2587,20 +2724,18 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ReductionOrMapperId = Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { - // Handle dependency type for depend clause. + // Handle dependency type for depend clause. ColonProtectionRAIIObject ColonRAII(*this); - Data.DepKind = - static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - Data.DepLinMapLoc = Tok.getLocation(); - - if (Data.DepKind == OMPC_DEPEND_unknown) { + Data.ExtraModifier = getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""); + Data.DepLinMapLastLoc = Tok.getLocation(); + if (Data.ExtraModifier == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); // Special processing for depend(source) clause. - if (DKind == OMPD_ordered && Data.DepKind == OMPC_DEPEND_source) { + if (DKind == OMPD_ordered && Data.ExtraModifier == OMPC_DEPEND_source) { // Parse ')'. T.consumeClose(); return false; @@ -2615,13 +2750,32 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, } } else if (Kind == OMPC_linear) { // Try to parse modifier if any. + Data.ExtraModifier = OMPC_LINEAR_val; if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { - Data.LinKind = static_cast<OpenMPLinearClauseKind>( - getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); - Data.DepLinMapLoc = ConsumeToken(); + Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + Data.DepLinMapLastLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; } + } else if (Kind == OMPC_lastprivate) { + // Try to parse modifier if any. + Data.ExtraModifier = OMPC_LASTPRIVATE_unknown; + // Conditional modifier allowed only in OpenMP 5.0 and not supported in + // distribute and taskloop based directives. + if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) && + !isOpenMPTaskLoopDirective(DKind)) && + Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) { + Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + Data.DepLinMapLastLoc = Tok.getLocation(); + if (Data.ExtraModifier == OMPC_LASTPRIVATE_unknown) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + ConsumeToken(); + } + assert(Tok.is(tok::colon) && "Expected colon."); + Data.ColonLoc = ConsumeToken(); + } } else if (Kind == OMPC_map) { // Handle map type for map clause. ColonProtectionRAIIObject ColonRAII(*this); @@ -2629,7 +2783,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // The first identifier may be a list item, a map-type or a // map-type-modifier. The map-type can also be delete which has the same // spelling of the C++ delete keyword. - Data.DepLinMapLoc = Tok.getLocation(); + Data.ExtraModifier = OMPC_MAP_unknown; + Data.DepLinMapLastLoc = Tok.getLocation(); // Check for presence of a colon in the map clause. TentativeParsingAction TPA(*this); @@ -2649,8 +2804,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, else SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch); } - if (Data.MapType == OMPC_MAP_unknown) { - Data.MapType = OMPC_MAP_tofrom; + if (Data.ExtraModifier == OMPC_MAP_unknown) { + Data.ExtraModifier = OMPC_MAP_tofrom; Data.IsMapTypeImplicit = true; } @@ -2716,8 +2871,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, (Kind != OMPC_reduction && Kind != OMPC_task_reduction && Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) || (Kind == OMPC_reduction && !InvalidReductionId) || - (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown) || - (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown); + (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || + (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -2767,7 +2922,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.RLoc = Tok.getLocation(); if (!T.consumeClose()) Data.RLoc = T.getCloseLocation(); - return (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown && + return (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown && Vars.empty()) || (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || (MustHaveTail && !Data.TailExpr) || InvalidReductionId || @@ -2837,8 +2992,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc); return Actions.ActOnOpenMPVarListClause( Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, - Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.DepKind, - Data.LinKind, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, - Data.MapType, Data.IsMapTypeImplicit, Data.DepLinMapLoc); + Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, + Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, + Data.IsMapTypeImplicit, Data.DepLinMapLastLoc); } diff --git a/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp index cdbf697cf7f1..df411e1928d6 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp @@ -734,7 +734,7 @@ void Parser::HandlePragmaMSVtorDisp() { uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); Sema::PragmaMsStackAction Action = static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); - MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF); + MSVtorDispMode Mode = MSVtorDispMode(Value & 0xFFFF); SourceLocation PragmaLoc = ConsumeAnnotationToken(); Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode); } diff --git a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp index 727ab75adae8..0339328ca513 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp @@ -1191,6 +1191,99 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, return false; } +namespace { + +enum MisleadingStatementKind { MSK_if, MSK_else, MSK_for, MSK_while }; + +struct MisleadingIndentationChecker { + Parser &P; + SourceLocation StmtLoc; + SourceLocation PrevLoc; + unsigned NumDirectives; + MisleadingStatementKind Kind; + bool ShouldSkip; + MisleadingIndentationChecker(Parser &P, MisleadingStatementKind K, + SourceLocation SL) + : P(P), StmtLoc(SL), PrevLoc(P.getCurToken().getLocation()), + NumDirectives(P.getPreprocessor().getNumDirectives()), Kind(K), + ShouldSkip(P.getCurToken().is(tok::l_brace)) { + if (!P.MisleadingIndentationElseLoc.isInvalid()) { + StmtLoc = P.MisleadingIndentationElseLoc; + P.MisleadingIndentationElseLoc = SourceLocation(); + } + if (Kind == MSK_else && !ShouldSkip) + P.MisleadingIndentationElseLoc = SL; + } + + /// Compute the column number will aligning tabs on TabStop (-ftabstop), this + /// gives the visual indentation of the SourceLocation. + static unsigned getVisualIndentation(SourceManager &SM, SourceLocation Loc) { + unsigned TabStop = SM.getDiagnostics().getDiagnosticOptions().TabStop; + + unsigned ColNo = SM.getSpellingColumnNumber(Loc); + if (ColNo == 0 || TabStop == 1) + return ColNo; + + std::pair<FileID, unsigned> FIDAndOffset = SM.getDecomposedLoc(Loc); + + bool Invalid; + StringRef BufData = SM.getBufferData(FIDAndOffset.first, &Invalid); + if (Invalid) + return 0; + + const char *EndPos = BufData.data() + FIDAndOffset.second; + // FileOffset are 0-based and Column numbers are 1-based + assert(FIDAndOffset.second + 1 >= ColNo && + "Column number smaller than file offset?"); + + unsigned VisualColumn = 0; // Stored as 0-based column, here. + // Loop from beginning of line up to Loc's file position, counting columns, + // expanding tabs. + for (const char *CurPos = EndPos - (ColNo - 1); CurPos != EndPos; + ++CurPos) { + if (*CurPos == '\t') + // Advance visual column to next tabstop. + VisualColumn += (TabStop - VisualColumn % TabStop); + else + VisualColumn++; + } + return VisualColumn + 1; + } + + void Check() { + Token Tok = P.getCurToken(); + if (P.getActions().getDiagnostics().isIgnored( + diag::warn_misleading_indentation, Tok.getLocation()) || + ShouldSkip || NumDirectives != P.getPreprocessor().getNumDirectives() || + Tok.isOneOf(tok::semi, tok::r_brace) || Tok.isAnnotation() || + Tok.getLocation().isMacroID() || PrevLoc.isMacroID() || + StmtLoc.isMacroID() || + (Kind == MSK_else && P.MisleadingIndentationElseLoc.isInvalid())) { + P.MisleadingIndentationElseLoc = SourceLocation(); + return; + } + if (Kind == MSK_else) + P.MisleadingIndentationElseLoc = SourceLocation(); + + SourceManager &SM = P.getPreprocessor().getSourceManager(); + unsigned PrevColNum = getVisualIndentation(SM, PrevLoc); + unsigned CurColNum = getVisualIndentation(SM, Tok.getLocation()); + unsigned StmtColNum = getVisualIndentation(SM, StmtLoc); + + if (PrevColNum != 0 && CurColNum != 0 && StmtColNum != 0 && + ((PrevColNum > StmtColNum && PrevColNum == CurColNum) || + !Tok.isAtStartOfLine()) && + SM.getPresumedLineNumber(StmtLoc) != + SM.getPresumedLineNumber(Tok.getLocation()) && + (Tok.isNot(tok::identifier) || + P.getPreprocessor().LookAhead(0).isNot(tok::colon))) { + P.Diag(Tok.getLocation(), diag::warn_misleading_indentation) << Kind; + P.Diag(StmtLoc, diag::note_previous_statement); + } + } +}; + +} /// ParseIfStatement /// if-statement: [C99 6.8.4.1] @@ -1265,6 +1358,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + MisleadingIndentationChecker MIChecker(*this, MSK_if, IfLoc); + // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); @@ -1278,6 +1373,9 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } + if (Tok.isNot(tok::kw_else)) + MIChecker.Check(); + // Pop the 'if' scope if needed. InnerScope.Exit(); @@ -1305,12 +1403,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc); + EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); ElseStmt = ParseStatement(); + if (ElseStmt.isUsable()) + MIChecker.Check(); + // Pop the 'else' scope if needed. InnerScope.Exit(); } else if (Tok.is(tok::code_completion)) { @@ -1484,9 +1587,13 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc); + // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); + if (Body.isUsable()) + MIChecker.Check(); // Pop the body scope if needed. InnerScope.Exit(); WhileScope.Exit(); @@ -1918,9 +2025,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { if (C99orCXXorObjC) getCurScope()->decrementMSManglingNumber(); + MisleadingIndentationChecker MIChecker(*this, MSK_for, ForLoc); + // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); + if (Body.isUsable()) + MIChecker.Check(); + // Pop the body scope if needed. InnerScope.Exit(); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseStmtAsm.cpp b/contrib/llvm-project/clang/lib/Parse/ParseStmtAsm.cpp index 1153c2510b05..ea2c871d6a82 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseStmtAsm.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseStmtAsm.cpp @@ -547,12 +547,9 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { // We need an actual supported target. const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple(); - llvm::Triple::ArchType ArchTy = TheTriple.getArch(); const std::string &TT = TheTriple.getTriple(); const llvm::Target *TheTarget = nullptr; - bool UnsupportedArch = - (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64); - if (UnsupportedArch) { + if (!TheTriple.isX86()) { Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); } else { std::string Error; @@ -563,16 +560,19 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { assert(!LBraceLocs.empty() && "Should have at least one location here"); + SmallString<512> AsmString; + auto EmptyStmt = [&] { + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmString, + /*NumOutputs*/ 0, /*NumInputs*/ 0, + ConstraintRefs, ClobberRefs, Exprs, EndLoc); + }; // If we don't support assembly, or the assembly is empty, we don't // need to instantiate the AsmParser, etc. if (!TheTarget || AsmToks.empty()) { - return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(), - /*NumOutputs*/ 0, /*NumInputs*/ 0, - ConstraintRefs, ClobberRefs, Exprs, EndLoc); + return EmptyStmt(); } // Expand the tokens into a string buffer. - SmallString<512> AsmString; SmallVector<unsigned, 8> TokOffsets; if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) return StmtError(); @@ -582,12 +582,26 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { llvm::join(TO.Features.begin(), TO.Features.end(), ","); std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); - std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); + if (!MRI) { + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) + << "target MC unavailable"; + return EmptyStmt(); + } + // FIXME: init MCOptions from sanitizer flags here. + llvm::MCTargetOptions MCOptions; + std::unique_ptr<llvm::MCAsmInfo> MAI( + TheTarget->createMCAsmInfo(*MRI, TT, MCOptions)); // Get the instruction descriptor. std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo()); std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); std::unique_ptr<llvm::MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr)); + // Target MCTargetDesc may not be linked in clang-based tools. + if (!MAI || !MII | !MOFI || !STI) { + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) + << "target MC unavailable"; + return EmptyStmt(); + } llvm::SourceMgr TempSrcMgr; llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); @@ -602,10 +616,14 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { std::unique_ptr<llvm::MCAsmParser> Parser( createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); - // FIXME: init MCOptions from sanitizer flags here. - llvm::MCTargetOptions MCOptions; std::unique_ptr<llvm::MCTargetAsmParser> TargetParser( TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions)); + // Target AsmParser may not be linked in clang-based tools. + if (!TargetParser) { + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) + << "target ASM parser unavailable"; + return EmptyStmt(); + } std::unique_ptr<llvm::MCInstPrinter> IP( TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI)); @@ -725,7 +743,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprResult AsmString(ParseAsmStringLiteral()); + ExprResult AsmString(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); // Check if GNU-style InlineAsm is disabled. // Error on anything other than empty string. @@ -805,7 +823,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { // Parse the asm-string list for clobbers if present. if (!AteExtraColon && isTokenStringLiteral()) { while (1) { - ExprResult Clobber(ParseAsmStringLiteral()); + ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); if (Clobber.isInvalid()) break; @@ -902,7 +920,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, } else Names.push_back(nullptr); - ExprResult Constraint(ParseAsmStringLiteral()); + ExprResult Constraint(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); if (Constraint.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return true; diff --git a/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp index 928bc5aa25b3..1b9301b6591d 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -130,7 +131,9 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( if (TryConsumeToken(tok::kw_requires)) { OptionalRequiresClauseConstraintER = - Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); if (!OptionalRequiresClauseConstraintER.isUsable()) { // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); @@ -254,8 +257,12 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( }); LateParsedAttrList LateParsedAttrs(true); - if (DeclaratorInfo.isFunctionDeclarator()) + if (DeclaratorInfo.isFunctionDeclarator()) { + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(DeclaratorInfo); + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + } if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo)) { @@ -492,7 +499,10 @@ Parser::ParseTemplateParameterList(const unsigned Depth, /// Determine whether the parser is at the start of a template /// type parameter. -bool Parser::isStartOfTemplateTypeParameter() { +/// \param ScopeError will receive true if there was an error parsing a +/// scope specifier at the current location. +bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { + ScopeError = false; if (Tok.is(tok::kw_class)) { // "class" may be the start of an elaborated-type-specifier or a // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. @@ -525,6 +535,40 @@ bool Parser::isStartOfTemplateTypeParameter() { } } + bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); + CXXScopeSpec SS; + ScopeError = + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false, + /*MayBePseudoDestructor=*/nullptr, + // If this is not a type-constraint, then + // this scope-spec is part of the typename + // of a non-type template parameter + /*IsTypename=*/true, /*LastII=*/nullptr, + // We won't find concepts in + // non-namespaces anyway, so might as well + // parse this correctly for possible type + // names. + /*OnlyNamespace=*/false); + if (ScopeError) + return false; + if (TryAnnotateTypeConstraint(SS)) + return false; + bool IsTypeConstraint = isTypeConstraintAnnotation(); + if (!IsTypeConstraint && SS.isNotEmpty()) { + // This isn't a type-constraint but we've already parsed this scope + // specifier - annotate it. + AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation); + return false; + } + + if (IsTypeConstraint && + // Next token might be 'auto' or 'decltype', indicating that this + // type-constraint is in fact part of a placeholder-type-specifier of a + // non-type template parameter. + !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) + return true; + // 'typedef' is a reasonably-common typo/thinko for 'typename', and is // ill-formed otherwise. if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef)) @@ -568,24 +612,37 @@ bool Parser::isStartOfTemplateTypeParameter() { /// type-parameter /// parameter-declaration /// -/// type-parameter: (see below) -/// 'class' ...[opt] identifier[opt] -/// 'class' identifier[opt] '=' type-id -/// 'typename' ...[opt] identifier[opt] -/// 'typename' identifier[opt] '=' type-id -/// 'template' '<' template-parameter-list '>' -/// 'class' ...[opt] identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] -/// = id-expression +/// type-parameter: (See below) +/// type-parameter-key ...[opt] identifier[opt] +/// type-parameter-key identifier[opt] = type-id +/// (C++2a) type-constraint ...[opt] identifier[opt] +/// (C++2a) type-constraint identifier[opt] = type-id +/// 'template' '<' template-parameter-list '>' type-parameter-key +/// ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' type-parameter-key +/// identifier[opt] '=' id-expression +/// +/// type-parameter-key: +/// class +/// typename +/// NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if (isStartOfTemplateTypeParameter()) { - // Is there just a typo in the input code? ('typedef' instead of 'typename') + // We could be facing a type-constraint, which (could) start a type parameter. + // Annotate it now (we might end up not using it if we determine this + // type-constraint is in fact part of a placeholder-type-specifier of a + // non-type template parameter. + + bool ScopeError; + if (isStartOfTemplateTypeParameter(ScopeError)) { + // Is there just a typo in the input code? ('typedef' instead of + // 'typename') if (Tok.is(tok::kw_typedef)) { Diag(Tok.getLocation(), diag::err_expected_template_parameter); Diag(Tok.getLocation(), diag::note_meant_to_use_typename) << FixItHint::CreateReplacement(CharSourceRange::getCharRange( - Tok.getLocation(), Tok.getEndLoc()), + Tok.getLocation(), + Tok.getEndLoc()), "typename"); Tok.setKind(tok::kw_typename); @@ -593,7 +650,26 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { return ParseTypeParameter(Depth, Position); } - + if (ScopeError) { + // We return an invalid parameter as opposed to null to avoid having bogus + // diagnostics about an empty template parameter list. + // FIXME: Fix ParseTemplateParameterList to better handle nullptr results + // from here. + // Return a NTTP as if there was an error in a scope specifier, the user + // probably meant to write the type of a NTTP. + DeclSpec DS(getAttrFactory()); + DS.SetTypeSpecError(); + Declarator D(DS, DeclaratorContext::TemplateParamContext); + D.SetIdentifier(nullptr, Tok.getLocation()); + D.setInvalidType(true); + NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter( + getCurScope(), D, Depth, Position, /*EqualLoc=*/SourceLocation(), + /*DefaultArg=*/nullptr); + ErrorParam->setInvalidDecl(true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, + StopAtSemi | StopBeforeMatch); + return ErrorParam; + } if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -603,6 +679,56 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { return ParseNonTypeTemplateParameter(Depth, Position); } +/// Check whether the current token is a template-id annotation denoting a +/// type-constraint. +bool Parser::isTypeConstraintAnnotation() { + if (Tok.isNot(tok::annot_template_id)) + return false; + const auto *ExistingAnnot = + static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + return ExistingAnnot->Kind == TNK_Concept_template; +} + +/// Try parsing a type-constraint construct at the current location, after the +/// optional scope specifier. +/// +/// type-constraint: +/// nested-name-specifier[opt] concept-name +/// nested-name-specifier[opt] concept-name +/// '<' template-argument-list[opt] '>'[opt] +/// +/// \returns true if an error occurred, and false otherwise. +bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) { + if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier)) + return false; + + UnqualifiedId PossibleConceptName; + PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(), + Tok.getLocation()); + + TemplateTy PossibleConcept; + bool MemberOfUnknownSpecialization = false; + auto TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + PossibleConceptName, + /*ObjectType=*/ParsedType(), + /*EnteringContext=*/false, + PossibleConcept, + MemberOfUnknownSpecialization); + assert(!MemberOfUnknownSpecialization + && "Member when we only allowed namespace scope qualifiers??"); + if (!PossibleConcept || TNK != TNK_Concept_template) + return false; + + // At this point we're sure we're dealing with a constrained parameter. It + // may or may not have a template parameter list following the concept name. + return AnnotateTemplateIdToken(PossibleConcept, TNK, SS, + /*TemplateKWLoc=*/SourceLocation(), + PossibleConceptName, + /*AllowTypeAnnotation=*/false, + /*TypeConstraint=*/true); +} + /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]). /// Other kinds of template parameters are parsed in /// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter. @@ -613,12 +739,25 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { - assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) && - "A type-parameter starts with 'class' or 'typename'"); - - // Consume the 'class' or 'typename' keyword. - bool TypenameKeyword = Tok.is(tok::kw_typename); - SourceLocation KeyLoc = ConsumeToken(); + assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) && + "A type-parameter starts with 'class', 'typename' or a " + "type-constraint"); + + TemplateIdAnnotation *TypeConstraint = nullptr; + bool TypenameKeyword = false; + SourceLocation KeyLoc; + if (Tok.is(tok::annot_template_id)) { + // Consume the 'type-constraint'. + TypeConstraint = + static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + assert(TypeConstraint->Kind == TNK_Concept_template && + "stray non-concept template-id annotation"); + KeyLoc = ConsumeAnnotationToken(); + } else { + // Consume the 'class' or 'typename' keyword. + TypenameKeyword = Tok.is(tok::kw_typename); + KeyLoc = ConsumeToken(); + } // Grab the ellipsis (if given). SourceLocation EllipsisLoc; @@ -658,9 +797,19 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { DefaultArg = ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArgContext).get(); - return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc, - KeyLoc, ParamName, NameLoc, Depth, Position, - EqualLoc, DefaultArg); + NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), + TypenameKeyword, EllipsisLoc, + KeyLoc, ParamName, NameLoc, + Depth, Position, EqualLoc, + DefaultArg, + TypeConstraint != nullptr); + + if (TypeConstraint) + Actions.ActOnTypeConstraint(TypeConstraint, + cast<TemplateTypeParmDecl>(NewDecl), + EllipsisLoc); + + return NewDecl; } /// ParseTemplateTemplateParameter - Handle the parsing of template @@ -823,7 +972,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // Create the parameter. return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, - Depth, Position, EqualLoc, + Depth, Position, EqualLoc, DefaultArg.get()); } @@ -1099,6 +1248,10 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, /// simple-template-id is always replaced with a template-id /// annotation token. /// +/// \param TypeConstraint if true, then this is actually a type-constraint, +/// meaning that the template argument list can be omitted (and the template in +/// question must be a concept). +/// /// If an unrecoverable parse error occurs and no annotation token can be /// formed, this function returns true. /// @@ -1106,10 +1259,15 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &TemplateName, - bool AllowTypeAnnotation) { + bool AllowTypeAnnotation, + bool TypeConstraint) { assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); - assert(Template && Tok.is(tok::less) && + assert(Template && (Tok.is(tok::less) || TypeConstraint) && "Parser isn't at the beginning of a template-id"); + assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be " + "a type annotation"); + assert((!TypeConstraint || TNK == TNK_Concept_template) && "type-constraint " + "must accompany a concept name"); // Consume the template-name. SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); @@ -1117,17 +1275,19 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, - TemplateArgs, - RAngleLoc); - - if (Invalid) { - // If we failed to parse the template ID but skipped ahead to a >, we're not - // going to be able to form a token annotation. Eat the '>' if present. - TryConsumeToken(tok::greater); - // FIXME: Annotate the token stream so we don't produce the same errors - // again if we're doing this annotation as part of a tentative parse. - return true; + if (!TypeConstraint || Tok.is(tok::less)) { + bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, + TemplateArgs, + RAngleLoc); + + if (Invalid) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + TryConsumeToken(tok::greater); + // FIXME: Annotate the token stream so we don't produce the same errors + // again if we're doing this annotation as part of a tentative parse. + return true; + } } ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); @@ -1365,8 +1525,9 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast); - if (ExprArg.isInvalid() || !ExprArg.get()) + if (ExprArg.isInvalid() || !ExprArg.get()) { return ParsedTemplateArgument(); + } return ParsedTemplateArgument(ParsedTemplateArgument::NonType, ExprArg.get(), Loc); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp index e2e16ca63d1e..4d69fb4693fb 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp @@ -1031,6 +1031,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; } @@ -2014,7 +2018,6 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, /// 'throw' '(' type-id-list[opt] ')' /// Parser::TPResult Parser::TryParseFunctionDeclarator() { - // The '(' is already parsed. TPResult TPR = TryParseParameterDeclarationClause(); @@ -2066,9 +2069,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; } diff --git a/contrib/llvm-project/clang/lib/Parse/Parser.cpp b/contrib/llvm-project/clang/lib/Parse/Parser.cpp index 2645f27e656f..4249de361b89 100644 --- a/contrib/llvm-project/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm-project/clang/lib/Parse/Parser.cpp @@ -278,6 +278,10 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { case tok::annot_pragma_openmp: case tok::annot_pragma_openmp_end: // Stop before an OpenMP pragma boundary. + if (OpenMPDirectiveParsing) + return false; + ConsumeAnnotationToken(); + break; case tok::annot_module_begin: case tok::annot_module_end: case tok::annot_module_include: @@ -799,7 +803,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; - ExprResult Result(ParseSimpleAsm(&EndLoc)); + ExprResult Result(ParseSimpleAsm(/*ForAsmLabel*/ false, &EndLoc)); // Check if GNU-style InlineAsm is disabled. // Empty asm string is allowed because it will not introduce @@ -1463,11 +1467,14 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { /// ParseAsmStringLiteral - This is just a normal string-literal, but is not /// allowed to be a wide string, and is not subject to character translation. +/// Unlike GCC, we also diagnose an empty string literal when parsing for an +/// asm label as opposed to an asm statement, because such a construct does not +/// behave well. /// /// [GNU] asm-string-literal: /// string-literal /// -ExprResult Parser::ParseAsmStringLiteral() { +ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal) << /*Source='in...'*/0 << "'asm'"; @@ -1483,6 +1490,11 @@ ExprResult Parser::ParseAsmStringLiteral() { << SL->getSourceRange(); return ExprError(); } + if (ForAsmLabel && SL->getString().empty()) { + Diag(Tok, diag::err_asm_operand_wide_string_literal) + << 2 /* an empty */ << SL->getSourceRange(); + return ExprError(); + } } return AsmString; } @@ -1492,7 +1504,7 @@ ExprResult Parser::ParseAsmStringLiteral() { /// [GNU] simple-asm-expr: /// 'asm' '(' asm-string-literal ')' /// -ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { +ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) { assert(Tok.is(tok::kw_asm) && "Not an asm!"); SourceLocation Loc = ConsumeToken(); @@ -1512,7 +1524,7 @@ ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { return ExprError(); } - ExprResult Result(ParseAsmStringLiteral()); + ExprResult Result(ParseAsmStringLiteral(ForAsmLabel)); if (!Result.isInvalid()) { // Close the paren and get the location of the end bracket |