diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-18 20:30:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-04-06 20:11:55 +0000 |
commit | 5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch) | |
tree | 1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/clang/lib/Parse | |
parent | 3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff) | |
parent | 312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff) |
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp | 5 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp | 307 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp | 79 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp | 116 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp | 227 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseInit.cpp | 8 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp | 64 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp | 527 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp | 205 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp | 183 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp | 83 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp | 15 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp | 31 | ||||
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/Parser.cpp | 70 |
14 files changed, 1510 insertions, 410 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp index 4951eb9aa280..573c90a36eea 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -395,9 +395,10 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { DefArgResult = ParseBraceInitializer(); } else DefArgResult = ParseAssignmentExpression(); - DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); + DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult, Param); if (DefArgResult.isInvalid()) { - Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc, + /*DefaultArg=*/nullptr); } else { if (Tok.isNot(tok::eof) || Tok.getEofData() != Param) { // The last two tokens are the terminator and the saved value of diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp index cf1e3a94de7f..ed006f9d67de 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -83,7 +84,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, DeclaratorContext Context, /// Normalizes an attribute name by dropping prefixed and suffixed __. static StringRef normalizeAttrName(StringRef Name) { - if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__")) return Name.drop_front(2).drop_back(2); return Name; } @@ -288,6 +289,16 @@ static bool attributeHasIdentifierArg(const IdentifierInfo &II) { #undef CLANG_ATTR_IDENTIFIER_ARG_LIST } +/// Determine whether the given attribute has an identifier argument. +static ParsedAttributeArgumentsProperties +attributeStringLiteralListArg(const IdentifierInfo &II) { +#define CLANG_ATTR_STRING_LITERAL_ARG_LIST + return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(0); +#undef CLANG_ATTR_STRING_LITERAL_ARG_LIST +} + /// Determine whether the given attribute has a variadic identifier argument. static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) { #define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST @@ -371,6 +382,81 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, ScopeName, ScopeLoc, nullptr, 0, Form); } +ExprResult +Parser::ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName) { + if (Tok.is(tok::l_paren)) { + BalancedDelimiterTracker Paren(*this, tok::l_paren); + Paren.consumeOpen(); + ExprResult Res = ParseUnevaluatedStringInAttribute(AttrName); + Paren.consumeClose(); + return Res; + } + if (!isTokenStringLiteral()) { + Diag(Tok.getLocation(), diag::err_expected_string_literal) + << /*in attribute...*/ 4 << AttrName.getName(); + return ExprError(); + } + return ParseUnevaluatedStringLiteralExpression(); +} + +bool Parser::ParseAttributeArgumentList( + const IdentifierInfo &AttrName, SmallVectorImpl<Expr *> &Exprs, + ParsedAttributeArgumentsProperties ArgsProperties) { + bool SawError = false; + unsigned Arg = 0; + while (true) { + ExprResult Expr; + if (ArgsProperties.isStringLiteralArg(Arg)) { + Expr = ParseUnevaluatedStringInAttribute(AttrName); + } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Expr = ParseBraceInitializer(); + } else { + Expr = ParseAssignmentExpression(); + } + Expr = Actions.CorrectDelayedTyposInExpr(Expr); + + if (Tok.is(tok::ellipsis)) + Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); + else if (Tok.is(tok::code_completion)) { + // There's nothing to suggest in here as we parsed a full expression. + // Instead fail and propagate the error since caller might have something + // the suggest, e.g. signature help in function call. Note that this is + // performed before pushing the \p Expr, so that signature help can report + // current argument correctly. + SawError = true; + cutOffParsing(); + break; + } + + if (Expr.isInvalid()) { + SawError = true; + break; + } + + Exprs.push_back(Expr.get()); + + if (Tok.isNot(tok::comma)) + break; + // Move to the next argument, remember where the comma was. + Token Comma = Tok; + ConsumeToken(); + checkPotentialAngleBracketDelimiter(Comma); + Arg++; + } + + if (SawError) { + // Ensure typos get diagnosed when errors were encountered while parsing the + // expression list. + for (auto &E : Exprs) { + ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E); + if (Expr.isUsable()) + E = Expr.get(); + } + } + return SawError; +} + unsigned Parser::ParseAttributeArgsCommon( IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, @@ -463,9 +549,9 @@ unsigned Parser::ParseAttributeArgsCommon( : Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprVector ParsedExprs; - if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(), - /*FailImmediatelyOnInvalidExpr=*/true, - /*EarlyTypoCorrection=*/true)) { + ParsedAttributeArgumentsProperties ArgProperties = + attributeStringLiteralListArg(*AttrName); + if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) { SkipUntil(tok::r_paren, StopAtSemi); return 0; } @@ -1230,31 +1316,19 @@ void Parser::ParseAvailabilityAttribute( } ConsumeToken(); if (Keyword == Ident_message || Keyword == Ident_replacement) { - if (Tok.isNot(tok::string_literal)) { + if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal) << /*Source='availability attribute'*/2; SkipUntil(tok::r_paren, StopAtSemi); return; } - if (Keyword == Ident_message) - MessageExpr = ParseStringLiteralExpression(); - else - ReplacementExpr = ParseStringLiteralExpression(); - // Also reject wide string literals. - if (StringLiteral *MessageStringLiteral = - cast_or_null<StringLiteral>(MessageExpr.get())) { - if (!MessageStringLiteral->isOrdinary()) { - Diag(MessageStringLiteral->getSourceRange().getBegin(), - diag::err_expected_string_literal) - << /*Source='availability attribute'*/ 2; - SkipUntil(tok::r_paren, StopAtSemi); - return; - } - } - if (Keyword == Ident_message) + if (Keyword == Ident_message) { + MessageExpr = ParseUnevaluatedStringLiteralExpression(); break; - else + } else { + ReplacementExpr = ParseUnevaluatedStringLiteralExpression(); continue; + } } // Special handling of 'NA' only when applied to introduced or @@ -1422,7 +1496,7 @@ void Parser::ParseExternalSourceSymbolAttribute( else HasDefinedIn = true; - if (Tok.isNot(tok::string_literal)) { + if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal) << /*Source='external_source_symbol attribute'*/ 3 << /*language | source container | USR*/ ( @@ -1436,27 +1510,27 @@ void Parser::ParseExternalSourceSymbolAttribute( if (HadLanguage) { Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause) << Keyword; - ParseStringLiteralExpression(); + ParseUnevaluatedStringLiteralExpression(); continue; } - Language = ParseStringLiteralExpression(); + Language = ParseUnevaluatedStringLiteralExpression(); } else if (Keyword == Ident_USR) { if (HadUSR) { Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause) << Keyword; - ParseStringLiteralExpression(); + ParseUnevaluatedStringLiteralExpression(); continue; } - USR = ParseStringLiteralExpression(); + USR = ParseUnevaluatedStringLiteralExpression(); } else { assert(Keyword == Ident_defined_in && "Invalid clause keyword!"); if (HadDefinedIn) { Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause) << Keyword; - ParseStringLiteralExpression(); + ParseUnevaluatedStringLiteralExpression(); continue; } - DefinedInExpr = ParseStringLiteralExpression(); + DefinedInExpr = ParseUnevaluatedStringLiteralExpression(); } } while (TryConsumeToken(tok::comma)); @@ -1761,7 +1835,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, AL.setInvalid(); continue; } - if (!AL.isCXX11Attribute() && !AL.isC2xAttribute()) + if (!AL.isStandardAttributeSyntax()) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { if (WarnOnUnknownAttrs) @@ -1776,8 +1850,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) { for (const ParsedAttr &PA : Attrs) { - if (PA.isCXX11Attribute() || PA.isC2xAttribute() || - PA.isRegularKeywordAttribute()) + if (PA.isStandardAttributeSyntax() || PA.isRegularKeywordAttribute()) Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.isRegularKeywordAttribute() << PA.getRange(); } @@ -1939,6 +2012,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( RecordDecl *AnonRecord = nullptr; Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord); + Actions.ActOnDefinedDeclarationSpecifier(TheDecl); DS.complete(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; @@ -1947,6 +2021,9 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( return Actions.ConvertDeclToDeclGroup(TheDecl); } + if (DS.hasTagDefinition()) + Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl()); + if (DeclSpecStart) DS.SetRangeStart(*DeclSpecStart); @@ -2494,6 +2571,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } } + Sema::CUDATargetContextRAII X(Actions, Sema::CTCK_InitGlobalVar, ThisDecl); switch (TheInitKind) { // Parse declarator '=' initializer. case InitKind::Equal: { @@ -3210,17 +3288,6 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, return false; } -// Choose the apprpriate diagnostic error for why fixed point types are -// disabled, set the previous specifier, and mark as invalid. -static void SetupFixedPointError(const LangOptions &LangOpts, - const char *&PrevSpec, unsigned &DiagID, - bool &isInvalid) { - assert(!LangOpts.FixedPoint); - DiagID = diag::err_fixed_point_not_enabled; - PrevSpec = ""; // Not used by diagnostic - isInvalid = true; -} - /// ParseDeclarationSpecifiers /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] @@ -3326,9 +3393,9 @@ void Parser::ParseDeclarationSpecifiers( if (!AttrsLastTime) ProhibitAttributes(attrs); else { - // Reject C++11 / C2x attributes that aren't type attributes. + // Reject C++11 / C23 attributes that aren't type attributes. for (const ParsedAttr &PA : attrs) { - if (!PA.isCXX11Attribute() && !PA.isC2xAttribute() && + if (!PA.isCXX11Attribute() && !PA.isC23Attribute() && !PA.isRegularKeywordAttribute()) continue; if (PA.getKind() == ParsedAttr::UnknownAttribute) @@ -3344,7 +3411,7 @@ void Parser::ParseDeclarationSpecifiers( } // We reject AT_LifetimeBound and AT_AnyX86NoCfCheck, even though they // are type attributes, because we historically haven't allowed these - // to be used as type attributes in C++11 / C2x syntax. + // to be used as type attributes in C++11 / C23 syntax. if (PA.isTypeAttr() && PA.getKind() != ParsedAttr::AT_LifetimeBound && PA.getKind() != ParsedAttr::AT_AnyX86NoCfCheck) continue; @@ -3960,11 +4027,11 @@ void Parser::ParseDeclarationSpecifiers( isStorageClass = true; break; case tok::kw_auto: - if (getLangOpts().CPlusPlus11) { + if (getLangOpts().CPlusPlus11 || getLangOpts().C23) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, Policy); - if (!isInvalid) + if (!isInvalid && !getLangOpts().C23) Diag(Tok, diag::ext_auto_storage_class) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); } else @@ -3996,15 +4063,15 @@ void Parser::ParseDeclarationSpecifiers( isStorageClass = true; break; case tok::kw_thread_local: - if (getLangOpts().C2x) - Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + if (getLangOpts().C23) + Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName(); // We map thread_local to _Thread_local in C23 mode so it retains the C // semantics rather than getting the C++ semantics. // FIXME: diagnostics will show _Thread_local when the user wrote // thread_local in source in C23 mode; we need some general way to // identify which way the user spelled the keyword in source. isInvalid = DS.SetStorageClassSpecThread( - getLangOpts().C2x ? DeclSpec::TSCS__Thread_local + getLangOpts().C23 ? DeclSpec::TSCS__Thread_local : DeclSpec::TSCS_thread_local, Loc, PrevSpec, DiagID); isStorageClass = true; @@ -4049,7 +4116,11 @@ void Parser::ParseDeclarationSpecifiers( ExprResult ExplicitExpr(static_cast<Expr *>(nullptr)); BalancedDelimiterTracker Tracker(*this, tok::l_paren); Tracker.consumeOpen(); - ExplicitExpr = ParseConstantExpression(); + + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + ExplicitExpr = ParseConstantExpressionInExprEvalContext(); ConsumedEnd = Tok.getLocation(); if (ExplicitExpr.isUsable()) { CloseParenLoc = Tok.getLocation(); @@ -4193,27 +4264,24 @@ void Parser::ParseDeclarationSpecifiers( DiagID, Policy); break; case tok::kw__Accum: - if (!getLangOpts().FixedPoint) { - SetupFixedPointError(getLangOpts(), PrevSpec, DiagID, isInvalid); - } else { - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_accum, Loc, PrevSpec, - DiagID, Policy); - } + assert(getLangOpts().FixedPoint && + "This keyword is only used when fixed point types are enabled " + "with `-ffixed-point`"); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_accum, Loc, PrevSpec, DiagID, + Policy); break; case tok::kw__Fract: - if (!getLangOpts().FixedPoint) { - SetupFixedPointError(getLangOpts(), PrevSpec, DiagID, isInvalid); - } else { - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_fract, Loc, PrevSpec, - DiagID, Policy); - } + assert(getLangOpts().FixedPoint && + "This keyword is only used when fixed point types are enabled " + "with `-ffixed-point`"); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_fract, Loc, PrevSpec, DiagID, + Policy); break; case tok::kw__Sat: - if (!getLangOpts().FixedPoint) { - SetupFixedPointError(getLangOpts(), PrevSpec, DiagID, isInvalid); - } else { - isInvalid = DS.SetTypeSpecSat(Loc, PrevSpec, DiagID); - } + assert(getLangOpts().FixedPoint && + "This keyword is only used when fixed point types are enabled " + "with `-ffixed-point`"); + isInvalid = DS.SetTypeSpecSat(Loc, PrevSpec, DiagID); break; case tok::kw___float128: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, @@ -4240,8 +4308,8 @@ void Parser::ParseDeclarationSpecifiers( DiagID, Policy); break; case tok::kw_bool: - if (getLangOpts().C2x) - Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + if (getLangOpts().C23) + Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName(); [[fallthrough]]; case tok::kw__Bool: if (Tok.is(tok::kw__Bool) && !getLangOpts().C99) @@ -4364,7 +4432,7 @@ void Parser::ParseDeclarationSpecifiers( continue; break; - // C2x/GNU typeof support. + // C23/GNU typeof support. case tok::kw_typeof: case tok::kw_typeof_unqual: ParseTypeofSpecifier(DS); @@ -4446,6 +4514,9 @@ void Parser::ParseDeclarationSpecifiers( break; case tok::kw_groupshared: + case tok::kw_in: + case tok::kw_inout: + case tok::kw_out: // NOTE: ParseHLSLQualifiers will consume the qualifier token. ParseHLSLQualifiers(DS.getAttributes()); continue; @@ -4511,7 +4582,7 @@ void Parser::ParseDeclarationSpecifiers( /// not to the declaration of a struct. /// /// struct-declaration: -/// [C2x] attributes-specifier-seq[opt] +/// [C23] attributes-specifier-seq[opt] /// specifier-qualifier-list struct-declarator-list /// [GNU] __extension__ struct-declaration /// [GNU] specifier-qualifier-list @@ -4546,7 +4617,7 @@ void Parser::ParseStructDeclaration( // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { - // C2x 6.7.2.1p9 : "The optional attribute specifier sequence in a + // C23 6.7.2.1p9 : "The optional attribute specifier sequence in a // member declaration appertains to each of the members declared by the // member declarator list; it shall not appear if the optional member // declarator list is omitted." @@ -4666,6 +4737,11 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_openacc)) { + ParseOpenACCDirectiveDecl(); + continue; + } + if (tok::isPragmaAnnotation(Tok.getKind())) { Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl) << DeclSpec::getSpecifierName( @@ -4934,7 +5010,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd()); - if (!getLangOpts().ObjC) { + if (!getLangOpts().ObjC && !getLangOpts().C23) { if (getLangOpts().CPlusPlus11) Diag(ColonLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type) << BaseRange; @@ -5384,7 +5460,7 @@ bool Parser::isTypeSpecifierQualifier() { // GNU attributes support. case tok::kw___attribute: - // C2x/GNU typeof support. + // C23/GNU typeof support. case tok::kw_typeof: case tok::kw_typeof_unqual: @@ -5477,7 +5553,6 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___read_write: case tok::kw___write_only: case tok::kw___funcref: - case tok::kw_groupshared: return true; case tok::kw_private: @@ -5486,6 +5561,13 @@ bool Parser::isTypeSpecifierQualifier() { // C11 _Atomic case tok::kw__Atomic: return true; + + // HLSL type qualifiers + case tok::kw_groupshared: + case tok::kw_in: + case tok::kw_inout: + case tok::kw_out: + return getLangOpts().HLSL; } } @@ -5660,7 +5742,7 @@ bool Parser::isDeclarationSpecifier( case tok::kw_static_assert: case tok::kw__Static_assert: - // C2x/GNU typeof support. + // C23/GNU typeof support. case tok::kw_typeof: case tok::kw_typeof_unqual: @@ -5760,8 +5842,7 @@ bool Parser::isDeclarationSpecifier( bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, DeclSpec::FriendSpecified IsFriend, const ParsedTemplateInfo *TemplateInfo) { - TentativeParsingAction TPA(*this); - + RevertingTentativeParsingAction TPA(*this); // Parse the C++ scope specifier. CXXScopeSpec SS; if (TemplateInfo && TemplateInfo->TemplateParams) @@ -5770,7 +5851,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHasErrors=*/false, /*EnteringContext=*/true)) { - TPA.Revert(); return false; } @@ -5782,7 +5862,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, } else if (Tok.is(tok::annot_template_id)) { ConsumeAnnotationToken(); } else { - TPA.Revert(); return false; } @@ -5792,7 +5871,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, // Current class name must be followed by a left parenthesis. if (Tok.isNot(tok::l_paren)) { - TPA.Revert(); return false; } ConsumeParen(); @@ -5801,7 +5879,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, // that we have a constructor. if (Tok.is(tok::r_paren) || (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) { - TPA.Revert(); return true; } @@ -5810,7 +5887,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier(/*Disambiguate*/ false, /*OuterMightBeMessageSend*/ true)) { - TPA.Revert(); return true; } @@ -5831,9 +5907,17 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, // If we parsed a scope specifier as well as friend, // we might be parsing a friend constructor. bool IsConstructor = false; - if (isDeclarationSpecifier(IsFriend && !SS.isSet() - ? ImplicitTypenameContext::No - : ImplicitTypenameContext::Yes)) + ImplicitTypenameContext ITC = IsFriend && !SS.isSet() + ? ImplicitTypenameContext::No + : ImplicitTypenameContext::Yes; + // Constructors cannot have this parameters, but we support that scenario here + // to improve diagnostic. + if (Tok.is(tok::kw_this)) { + ConsumeToken(); + return isDeclarationSpecifier(ITC); + } + + if (isDeclarationSpecifier(ITC)) IsConstructor = true; else if (Tok.is(tok::identifier) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) { @@ -5902,8 +5986,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, break; } } - - TPA.Revert(); return IsConstructor; } @@ -5985,6 +6067,9 @@ void Parser::ParseTypeQualifierListOpt( break; case tok::kw_groupshared: + case tok::kw_in: + case tok::kw_inout: + case tok::kw_out: // NOTE: ParseHLSLQualifiers will consume the qualifier token. ParseHLSLQualifiers(DS.getAttributes()); continue; @@ -6596,7 +6681,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // Objective-C++: Detect C++ keywords and try to prevent further errors by // treating these keyword as valid member names. if (getLangOpts().ObjC && getLangOpts().CPlusPlus && - Tok.getIdentifierInfo() && + !Tok.isAnnotation() && Tok.getIdentifierInfo() && Tok.getIdentifierInfo()->isCPlusPlusKeyword(getLangOpts())) { Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), diag::err_expected_member_name_or_semi_objcxx_keyword) @@ -7022,7 +7107,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Diag(Tok, diag::err_argument_required_after_attribute); // OpenCL disallows functions without a prototype, but it doesn't enforce - // strict prototypes as in C2x because it allows a function definition to + // strict prototypes as in C23 because it allows a function definition to // have an identifier list. See OpenCL 3.0 6.11/g for more details. HasProto = ParamInfo.size() || getLangOpts().requiresStrictPrototypes() || getLangOpts().OpenCL; @@ -7205,9 +7290,9 @@ bool Parser::isFunctionDeclaratorIdentifierList() { void Parser::ParseFunctionDeclaratorIdentifierList( Declarator &D, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) { - // We should never reach this point in C2x or C++. + // We should never reach this point in C23 or C++. assert(!getLangOpts().requiresStrictPrototypes() && - "Cannot parse an identifier list in C2x or C++"); + "Cannot parse an identifier list in C23 or C++"); // If there was no identifier specified for the declarator, either we are in // an abstract-declarator, or we are in a parameter declarator which was found @@ -7281,6 +7366,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// [C++11] attribute-specifier-seq parameter-declaration +/// [C++2b] attribute-specifier-seq 'this' parameter-declaration /// void Parser::ParseParameterDeclarationClause( DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, @@ -7345,9 +7431,16 @@ void Parser::ParseParameterDeclarationClause( SourceLocation DSStart = Tok.getLocation(); + // Parse a C++23 Explicit Object Parameter + // We do that in all language modes to produce a better diagnostic. + SourceLocation ThisLoc; + if (getLangOpts().CPlusPlus && Tok.is(tok::kw_this)) + ThisLoc = ConsumeToken(); + ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(), AS_none, DeclSpecContext::DSC_normal, /*LateAttrs=*/nullptr, AllowImplicitTypename); + DS.takeAttributesFrom(ArgDeclSpecAttrs); // Parse the declarator. This is "PrototypeContext" or @@ -7361,6 +7454,9 @@ void Parser::ParseParameterDeclarationClause( : DeclaratorContext::Prototype); ParseDeclarator(ParmDeclarator); + if (ThisLoc.isValid()) + ParmDeclarator.SetRangeBegin(ThisLoc); + // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); if (getLangOpts().HLSL) @@ -7430,7 +7526,8 @@ void Parser::ParseParameterDeclarationClause( } // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); + Decl *Param = + Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator, ThisLoc); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in @@ -7467,7 +7564,8 @@ void Parser::ParseParameterDeclarationClause( } else { if (Tok.is(tok::l_paren) && NextToken().is(tok::l_brace)) { Diag(Tok, diag::err_stmt_expr_in_default_arg) << 0; - Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc, + /*DefaultArg=*/nullptr); // Skip the statement expression and continue parsing SkipUntil(tok::comma, StopBeforeMatch); continue; @@ -7476,7 +7574,8 @@ void Parser::ParseParameterDeclarationClause( } DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); if (DefArgResult.isInvalid()) { - Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc, + /*DefaultArg=*/nullptr); SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch); } else { // Inform the actions module about the default argument @@ -7614,7 +7713,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Parse the constant-expression or assignment-expression now (depending // on dialect). if (getLangOpts().CPlusPlus) { - NumElements = ParseConstantExpression(); + NumElements = ParseArrayBoundExpression(); } else { EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); @@ -7741,7 +7840,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) { /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression -/// [C2x] typeof-specifier: +/// [C23] typeof-specifier: /// typeof '(' typeof-specifier-argument ')' /// typeof_unqual '(' typeof-specifier-argument ')' /// @@ -7755,8 +7854,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool IsUnqual = Tok.is(tok::kw_typeof_unqual); const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (getLangOpts().C2x && !II->getName().startswith("__")) - Diag(Tok.getLocation(), diag::warn_c2x_compat_keyword) << Tok.getName(); + if (getLangOpts().C23 && !II->getName().starts_with("__")) + Diag(Tok.getLocation(), diag::warn_c23_compat_keyword) << Tok.getName(); Token OpTok = Tok; SourceLocation StartLoc = ConsumeToken(); @@ -7953,10 +8052,10 @@ void Parser::DiagnoseBitIntUse(const Token &Tok) { Diag(Loc, diag::warn_ext_int_deprecated) << FixItHint::CreateReplacement(Loc, "_BitInt"); } else { - // In C2x mode, diagnose that the use is not compatible with pre-C2x modes. + // In C23 mode, diagnose that the use is not compatible with pre-C23 modes. // Otherwise, diagnose that the use is a Clang extension. - if (getLangOpts().C2x) - Diag(Loc, diag::warn_c2x_compat_keyword) << Tok.getName(); + if (getLangOpts().C23) + Diag(Loc, diag::warn_c23_compat_keyword) << Tok.getName(); else Diag(Loc, diag::ext_bit_int) << getLangOpts().CPlusPlus; } diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp index d9ff6c42c502..910112ecae96 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -971,8 +972,8 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) { Diag(Tok, diag::ext_c11_feature) << Tok.getName(); if (Tok.is(tok::kw_static_assert)) { if (!getLangOpts().CPlusPlus) { - if (getLangOpts().C2x) - Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + if (getLangOpts().C23) + Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName(); else Diag(Tok, diag::ext_ms_static_assert) << FixItHint::CreateReplacement( Tok.getLocation(), "_Static_assert"); @@ -1004,7 +1005,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) { DiagVal = diag::warn_cxx14_compat_static_assert_no_message; else if (getLangOpts().CPlusPlus) DiagVal = diag::ext_cxx_static_assert_no_message; - else if (getLangOpts().C2x) + else if (getLangOpts().C23) DiagVal = diag::warn_c17_compat_static_assert_no_message; else DiagVal = diag::ext_c_static_assert_no_message; @@ -1022,7 +1023,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) { const Token &T = GetLookAheadToken(I); if (T.is(tok::r_paren)) break; - if (!tok::isStringLiteral(Tok.getKind())) { + if (!tokenIsLikeStringLiteral(T, getLangOpts()) || T.hasUDSuffix()) { ParseAsExpression = true; break; } @@ -1031,7 +1032,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) { if (ParseAsExpression) AssertMessage = ParseConstantExpressionInExprEvalContext(); - else if (tok::isStringLiteral(Tok.getKind())) + else if (tokenIsLikeStringLiteral(Tok, getLangOpts())) AssertMessage = ParseUnevaluatedStringLiteralExpression(); else { Diag(Tok, diag::err_expected_string_literal) @@ -1654,7 +1655,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void, - tok::kw___is_volatile)) + tok::kw___is_volatile, + tok::kw___reference_binds_to_temporary, + tok::kw___reference_constructs_from_temporary)) // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 // and Clang. Therefore, when we see the token sequence "struct @@ -2861,6 +2864,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, RecordDecl *AnonRecord = nullptr; Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( getCurScope(), AS, DS, DeclAttrs, TemplateParams, false, AnonRecord); + Actions.ActOnDefinedDeclarationSpecifier(TheDecl); DS.complete(TheDecl); if (AnonRecord) { Decl *decls[] = {AnonRecord, TheDecl}; @@ -2869,6 +2873,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return Actions.ConvertDeclToDeclGroup(TheDecl); } + if (DS.hasTagDefinition()) + Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl()); + ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs, DeclaratorContext::Member); if (TemplateInfo.TemplateParams) @@ -3225,13 +3232,21 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, assert(Tok.isOneOf(tok::equal, tok::l_brace) && "Data member initializer not starting with '=' or '{'"); + bool IsFieldInitialization = isa_and_present<FieldDecl>(D); + EnterExpressionEvaluationContext Context( Actions, - isa_and_present<FieldDecl>(D) + IsFieldInitialization ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed : Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D); - Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = true; + + // CWG2760 + // Default member initializers used to initialize a base or member subobject + // [...] are considered to be part of the function body + Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = + IsFieldInitialization; + if (TryConsumeToken(tok::equal, EqualLoc)) { if (Tok.is(tok::kw_delete)) { // In principle, an initializer of '= delete p;' is legal, but it will @@ -3414,6 +3429,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( case tok::annot_pragma_openmp: return ParseOpenMPDeclarativeDirectiveWithExtDecl( AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl); + case tok::annot_pragma_openacc: + return ParseOpenACCDirectiveDecl(); default: if (tok::isPragmaAnnotation(Tok.getKind())) { @@ -3968,7 +3985,11 @@ ExceptionSpecificationType Parser::tryParseExceptionSpecification( // There is an argument. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - NoexceptExpr = ParseConstantExpression(); + + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + NoexceptExpr = ParseConstantExpressionInExprEvalContext(); + T.consumeClose(); if (!NoexceptExpr.isInvalid()) { NoexceptExpr = @@ -4236,7 +4257,7 @@ Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc, case tok::code_completion: cutOffParsing(); Actions.CodeCompleteAttribute(getLangOpts().CPlusPlus ? ParsedAttr::AS_CXX11 - : ParsedAttr::AS_C2x, + : ParsedAttr::AS_C23, Completion, Scope); return nullptr; @@ -4287,7 +4308,7 @@ Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc, } } -void Parser::ParseOpenMPAttributeArgs(IdentifierInfo *AttrName, +void Parser::ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName, CachedTokens &OpenMPTokens) { // Both 'sequence' and 'directive' attributes require arguments, so parse the // open paren for the argument list. @@ -4325,7 +4346,7 @@ void Parser::ParseOpenMPAttributeArgs(IdentifierInfo *AttrName, // * An identifier (omp) for the attribute namespace followed by :: // * An identifier (directive) or an identifier (sequence). SourceLocation IdentLoc; - IdentifierInfo *Ident = TryParseCXX11AttributeIdentifier(IdentLoc); + const IdentifierInfo *Ident = TryParseCXX11AttributeIdentifier(IdentLoc); // If there is an identifier and it is 'omp', a double colon is required // followed by the actual identifier we're after. @@ -4394,7 +4415,7 @@ bool Parser::ParseCXX11AttributeArgs( SourceLocation LParenLoc = Tok.getLocation(); const LangOptions &LO = getLangOpts(); ParsedAttr::Form Form = - LO.CPlusPlus ? ParsedAttr::Form::CXX11() : ParsedAttr::Form::C2x(); + LO.CPlusPlus ? ParsedAttr::Form::CXX11() : ParsedAttr::Form::C23(); // Try parsing microsoft attributes if (getLangOpts().MicrosoftExt || getLangOpts().HLSL) { @@ -4407,10 +4428,8 @@ bool Parser::ParseCXX11AttributeArgs( // arguments. if (Form.getSyntax() != ParsedAttr::AS_Microsoft && !hasAttribute(LO.CPlusPlus ? AttributeCommonInfo::Syntax::AS_CXX11 - : AttributeCommonInfo::Syntax::AS_C2x, + : AttributeCommonInfo::Syntax::AS_C23, ScopeName, AttrName, getTargetInfo(), getLangOpts())) { - if (getLangOpts().MicrosoftExt || getLangOpts().HLSL) { - } // Eat the left paren, then skip to the ending right paren. ConsumeParen(); SkipUntil(tok::r_paren); @@ -4449,6 +4468,14 @@ bool Parser::ParseCXX11AttributeArgs( if (!Attrs.empty() && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) { ParsedAttr &Attr = Attrs.back(); + + // Ignore attributes that don't exist for the target. + if (!Attr.existsInTarget(getTargetInfo())) { + Diag(LParenLoc, diag::warn_unknown_attribute_ignored) << AttrName; + Attr.setInvalid(true); + return true; + } + // If the attribute is a standard or built-in attribute and we are // parsing an argument list, we need to determine whether this attribute // was allowed to have an argument list (such as [[deprecated]]), and how @@ -4471,7 +4498,7 @@ bool Parser::ParseCXX11AttributeArgs( return true; } -/// Parse a C++11 or C2x attribute-specifier. +/// Parse a C++11 or C23 attribute-specifier. /// /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' @@ -4499,8 +4526,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, CachedTokens &OpenMPTokens, SourceLocation *EndLoc) { if (Tok.is(tok::kw_alignas)) { - if (getLangOpts().C2x) - Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + if (getLangOpts().C23) + Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName(); else Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); ParseAlignmentSpecifier(Attrs, EndLoc); @@ -4523,8 +4550,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, Diag(OpenLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_attribute : diag::warn_ext_cxx11_attributes); } else { - Diag(OpenLoc, getLangOpts().C2x ? diag::warn_pre_c2x_compat_attributes - : diag::warn_ext_c2x_attributes); + Diag(OpenLoc, getLangOpts().C23 ? diag::warn_pre_c23_compat_attributes + : diag::warn_ext_c23_attributes); } ConsumeBracket(); @@ -4609,7 +4636,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), ScopeName, ScopeLoc, nullptr, 0, getLangOpts().CPlusPlus ? ParsedAttr::Form::CXX11() - : ParsedAttr::Form::C2x()); + : ParsedAttr::Form::C23()); AttrParsed = true; } @@ -4635,7 +4662,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, SkipUntil(tok::r_square); } -/// ParseCXX11Attributes - Parse a C++11 or C2x attribute-specifier-seq. +/// ParseCXX11Attributes - Parse a C++11 or C23 attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier @@ -4710,9 +4737,9 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { } ArgsVector ArgExprs; - if (Tok.is(tok::string_literal)) { + if (isTokenStringLiteral()) { // Easy case: uuid("...") -- quoted string. - ExprResult StringResult = ParseStringLiteralExpression(); + ExprResult StringResult = ParseUnevaluatedStringLiteralExpression(); if (StringResult.isInvalid()) return; ArgExprs.push_back(StringResult.get()); @@ -4767,7 +4794,7 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { Toks[0].setLiteralData(StrBuffer.data()); Toks[0].setLength(StrBuffer.size()); StringLiteral *UuidString = - cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get()); + cast<StringLiteral>(Actions.ActOnUnevaluatedStringLiteral(Toks).get()); ArgExprs.push_back(UuidString); } diff --git a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp index 75d04824d8b9..897810557976 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp @@ -23,6 +23,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" @@ -220,6 +221,15 @@ ExprResult Parser::ParseConstantExpression() { return ParseConstantExpressionInExprEvalContext(NotTypeCast); } +ExprResult Parser::ParseArrayBoundExpression() { + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + // If we parse the bound of a VLA... we parse a non-constant + // constant-expression! + Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true; + return ParseConstantExpressionInExprEvalContext(NotTypeCast); +} + ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); @@ -1010,7 +1020,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, if (getLangOpts().CPlusPlus) Diag(Tok, diag::warn_cxx98_compat_nullptr); else - Diag(Tok, getLangOpts().C2x ? diag::warn_c2x_compat_keyword + Diag(Tok, getLangOpts().C23 ? diag::warn_c23_compat_keyword : diag::ext_c_nullptr) << Tok.getName(); Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); @@ -1127,6 +1137,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, REVERTIBLE_TYPE_TRAIT(__is_unsigned); REVERTIBLE_TYPE_TRAIT(__is_void); REVERTIBLE_TYPE_TRAIT(__is_volatile); + REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary); + REVERTIBLE_TYPE_TRAIT(__reference_constructs_from_temporary); #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait)); #include "clang/Basic/TransformTypeTraits.def" @@ -1297,9 +1309,17 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] - Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); - ConsumeToken(); - break; + // Function local predefined macros are represented by PredefinedExpr except + // when Microsoft extensions are enabled and one of these macros is adjacent + // to a string literal or another one of these macros. + if (!(getLangOpts().MicrosoftExt && + tokenIsLikeStringLiteral(Tok, getLangOpts()) && + tokenIsLikeStringLiteral(NextToken(), getLangOpts()))) { + Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); + ConsumeToken(); + break; + } + [[fallthrough]]; // treat MS function local macros as concatenable strings case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: case tok::utf8_string_literal: @@ -1440,9 +1460,13 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // unary-expression: '__alignof' '(' type-name ')' case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' + // unary-expression: '__datasizeof' unary-expression + // unary-expression: '__datasizeof' '(' type-name ')' + case tok::kw___datasizeof: 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: + case tok::kw___builtin_vectorelements: if (NotPrimaryExpression) *NotPrimaryExpression = true; AllowSuffix = false; @@ -1553,6 +1577,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_typename: case tok::kw_typeof: case tok::kw___vector: + case tok::kw__Accum: + case tok::kw__Fract: + case tok::kw__Sat: #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" { @@ -2286,6 +2313,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' +/// [Clang] '__datasizeof' unary-expression +/// [Clang] '__datasizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' @@ -2295,7 +2324,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression -/// [C2x] typeof-specifier: +/// [C23] typeof-specifier: /// typeof '(' typeof-specifier-argument ')' /// typeof_unqual '(' typeof-specifier-argument ')' /// @@ -2314,9 +2343,10 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, SourceRange &CastRange) { assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual, tok::kw_sizeof, - tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof, - tok::kw_vec_step, - tok::kw___builtin_omp_required_simd_align) && + tok::kw___datasizeof, tok::kw___alignof, tok::kw_alignof, + tok::kw__Alignof, tok::kw_vec_step, + tok::kw___builtin_omp_required_simd_align, + tok::kw___builtin_vectorelements) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -2325,8 +2355,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, if (Tok.isNot(tok::l_paren)) { // If construct allows a form without parenthesis, user may forget to put // pathenthesis around type name. - if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, - tok::kw__Alignof)) { + if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___datasizeof, tok::kw___alignof, + tok::kw_alignof, tok::kw__Alignof)) { if (isTypeIdUnambiguously()) { DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); @@ -2429,15 +2459,18 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() { /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++11] 'sizeof' '...' '(' identifier ')' +/// [Clang] '__datasizeof' unary-expression +/// [Clang] '__datasizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// \endverbatim ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { - assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, - tok::kw__Alignof, tok::kw_vec_step, - tok::kw___builtin_omp_required_simd_align) && + assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___datasizeof, tok::kw___alignof, + tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, + tok::kw___builtin_omp_required_simd_align, + tok::kw___builtin_vectorelements) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -2492,8 +2525,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (getLangOpts().CPlusPlus && OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); - else if (getLangOpts().C2x && OpTok.is(tok::kw_alignof)) - Diag(OpTok, diag::warn_c2x_compat_keyword) << OpTok.getName(); + else if (getLangOpts().C23 && OpTok.is(tok::kw_alignof)) + Diag(OpTok, diag::warn_c23_compat_keyword) << OpTok.getName(); EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, @@ -2508,14 +2541,29 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { CastRange); UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; - if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) + switch (OpTok.getKind()) { + case tok::kw_alignof: + case tok::kw__Alignof: ExprKind = UETT_AlignOf; - else if (OpTok.is(tok::kw___alignof)) + break; + case tok::kw___alignof: ExprKind = UETT_PreferredAlignOf; - else if (OpTok.is(tok::kw_vec_step)) + break; + case tok::kw_vec_step: ExprKind = UETT_VecStep; - else if (OpTok.is(tok::kw___builtin_omp_required_simd_align)) + break; + case tok::kw___builtin_omp_required_simd_align: ExprKind = UETT_OpenMPRequiredSimdAlign; + break; + case tok::kw___datasizeof: + ExprKind = UETT_DataSizeOf; + break; + case tok::kw___builtin_vectorelements: + ExprKind = UETT_VectorElements; + break; + default: + break; + } if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), @@ -2795,22 +2843,22 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } - SourceLocExpr::IdentKind Kind = [&] { + SourceLocIdentKind Kind = [&] { switch (T) { case tok::kw___builtin_FILE: - return SourceLocExpr::File; + return SourceLocIdentKind::File; case tok::kw___builtin_FILE_NAME: - return SourceLocExpr::FileName; + return SourceLocIdentKind::FileName; case tok::kw___builtin_FUNCTION: - return SourceLocExpr::Function; + return SourceLocIdentKind::Function; case tok::kw___builtin_FUNCSIG: - return SourceLocExpr::FuncSig; + return SourceLocIdentKind::FuncSig; case tok::kw___builtin_LINE: - return SourceLocExpr::Line; + return SourceLocIdentKind::Line; case tok::kw___builtin_COLUMN: - return SourceLocExpr::Column; + return SourceLocIdentKind::Column; case tok::kw___builtin_source_location: - return SourceLocExpr::SourceLocStruct; + return SourceLocIdentKind::SourceLocStruct; default: llvm_unreachable("invalid keyword"); } @@ -3267,16 +3315,18 @@ ExprResult Parser::ParseUnevaluatedStringLiteralExpression() { ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral, bool Unevaluated) { - assert(isTokenStringLiteral() && "Not a string literal!"); + assert(tokenIsLikeStringLiteral(Tok, getLangOpts()) && + "Not a string-literal-like token!"); - // String concat. Note that keywords like __func__ and __FUNCTION__ are not - // considered to be strings for concatenation purposes. + // String concatenation. + // Note: some keywords like __FUNCTION__ are not considered to be strings + // for concatenation purposes, unless Microsoft extensions are enabled. SmallVector<Token, 4> StringToks; do { StringToks.push_back(Tok); - ConsumeStringToken(); - } while (isTokenStringLiteral()); + ConsumeAnyToken(); + } while (tokenIsLikeStringLiteral(Tok, getLangOpts())); if (Unevaluated) { assert(!AllowUserDefinedLiteral && "UDL are always evaluated"); @@ -3504,7 +3554,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); else if (Tok.is(tok::code_completion)) { // There's nothing to suggest in here as we parsed a full expression. - // Instead fail and propogate the error since caller might have something + // Instead fail and propagate the error since caller might have something // the suggest, e.g. signature help in function call. Note that this is // performed before pushing the \p Expr, so that signature help can report // current argument correctly. diff --git a/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp index b035bd9db9d5..ef9ea6575205 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp @@ -1311,18 +1311,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( D.takeAttributes(Attributes); } - // Helper to emit a warning if we see a CUDA host/device/global attribute - // after '(...)'. nvcc doesn't accept this. - auto WarnIfHasCUDATargetAttr = [&] { - if (getLangOpts().CUDA) - for (const ParsedAttr &A : Attributes) - if (A.getKind() == ParsedAttr::AT_CUDADevice || - A.getKind() == ParsedAttr::AT_CUDAHost || - A.getKind() == ParsedAttr::AT_CUDAGlobal) - Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position) - << A.getAttrName()->getName(); - }; - MultiParseScope TemplateParamScope(*this); if (Tok.is(tok::less)) { Diag(Tok, getLangOpts().CPlusPlus20 @@ -1377,91 +1365,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( bool HasSpecifiers = false; SourceLocation MutableLoc; - auto ParseConstexprAndMutableSpecifiers = [&] { - // GNU-style attributes must be parsed before the mutable specifier to - // be compatible with GCC. MSVC-style attributes must be parsed before - // the mutable specifier to be compatible with MSVC. - MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes); - // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update - // the DeclEndLoc. - SourceLocation ConstexprLoc; - SourceLocation ConstevalLoc; - SourceLocation StaticLoc; - - tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc, - ConstevalLoc, DeclEndLoc); - - DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro); - - addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS); - addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); - }; - - auto ParseLambdaSpecifiers = - [&](MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo, - SourceLocation EllipsisLoc) { - // Parse exception-specification[opt]. - ExceptionSpecificationType ESpecType = EST_None; - SourceRange ESpecRange; - SmallVector<ParsedType, 2> DynamicExceptions; - SmallVector<SourceRange, 2> DynamicExceptionRanges; - ExprResult NoexceptExpr; - CachedTokens *ExceptionSpecTokens; - - ESpecType = tryParseExceptionSpecification( - /*Delayed=*/false, ESpecRange, DynamicExceptions, - DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); - - if (ESpecType != EST_None) - DeclEndLoc = ESpecRange.getEnd(); - - // Parse attribute-specifier[opt]. - if (MaybeParseCXX11Attributes(Attributes)) - DeclEndLoc = Attributes.Range.getEnd(); - - // 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]. - if (Tok.is(tok::arrow)) { - FunLocalRangeEnd = Tok.getLocation(); - SourceRange Range; - TrailingReturnType = ParseTrailingReturnType( - Range, /*MayBeFollowedByDirectInit*/ false); - TrailingReturnTypeLoc = Range.getBegin(); - if (Range.getEnd().isValid()) - DeclEndLoc = Range.getEnd(); - } - - SourceLocation NoLoc; - D.AddTypeInfo( - DeclaratorChunk::getFunction( - /*HasProto=*/true, - /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), - ParamInfo.size(), EllipsisLoc, RParenLoc, - /*RefQualifierIsLvalueRef=*/true, - /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange, - DynamicExceptions.data(), DynamicExceptionRanges.data(), - DynamicExceptions.size(), - NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, - /*ExceptionSpecTokens*/ nullptr, - /*DeclsInPrototype=*/std::nullopt, LParenLoc, FunLocalRangeEnd, - D, TrailingReturnType, TrailingReturnTypeLoc, &DS), - std::move(Attributes), DeclEndLoc); - - Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); - - if (HasParentheses && Tok.is(tok::kw_requires)) - ParseTrailingRequiresClause(D); - }; - ParseScope Prototype(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | Scope::DeclScope); @@ -1511,18 +1414,104 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( << FixItHint::CreateInsertion(Tok.getLocation(), "() "); } - if (HasParentheses || HasSpecifiers) - ParseConstexprAndMutableSpecifiers(); + if (HasParentheses || HasSpecifiers) { + // GNU-style attributes must be parsed before the mutable specifier to + // be compatible with GCC. MSVC-style attributes must be parsed before + // the mutable specifier to be compatible with MSVC. + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes); + // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update + // the DeclEndLoc. + SourceLocation ConstexprLoc; + SourceLocation ConstevalLoc; + SourceLocation StaticLoc; + + tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc, + ConstevalLoc, DeclEndLoc); + + DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro); + + addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS); + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); + addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); + } Actions.ActOnLambdaClosureParameters(getCurScope(), ParamInfo); if (!HasParentheses) Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); - if (HasSpecifiers || HasParentheses) - ParseLambdaSpecifiers(ParamInfo, EllipsisLoc); + if (HasSpecifiers || HasParentheses) { + // Parse exception-specification[opt]. + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + SmallVector<ParsedType, 2> DynamicExceptions; + SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens; + + ESpecType = tryParseExceptionSpecification( + /*Delayed=*/false, ESpecRange, DynamicExceptions, + DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); + + if (ESpecType != EST_None) + DeclEndLoc = ESpecRange.getEnd(); + + // Parse attribute-specifier[opt]. + if (MaybeParseCXX11Attributes(Attributes)) + DeclEndLoc = Attributes.Range.getEnd(); + + // 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]. + if (Tok.is(tok::arrow)) { + FunLocalRangeEnd = Tok.getLocation(); + SourceRange Range; + TrailingReturnType = + ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit=*/false); + TrailingReturnTypeLoc = Range.getBegin(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + SourceLocation NoLoc; + D.AddTypeInfo(DeclaratorChunk::getFunction( + /*HasProto=*/true, + /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), + ParamInfo.size(), EllipsisLoc, RParenLoc, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, + ESpecRange, DynamicExceptions.data(), + DynamicExceptionRanges.data(), DynamicExceptions.size(), + NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, + /*ExceptionSpecTokens*/ nullptr, + /*DeclsInPrototype=*/std::nullopt, LParenLoc, + FunLocalRangeEnd, D, TrailingReturnType, + TrailingReturnTypeLoc, &DS), + std::move(Attributes), DeclEndLoc); + + Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); + + if (HasParentheses && Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + } - WarnIfHasCUDATargetAttr(); + // Emit a warning if we see a CUDA host/device/global attribute + // after '(...)'. nvcc doesn't accept this. + if (getLangOpts().CUDA) { + for (const ParsedAttr &A : Attributes) + if (A.getKind() == ParsedAttr::AT_CUDADevice || + A.getKind() == ParsedAttr::AT_CUDAHost || + A.getKind() == ParsedAttr::AT_CUDAGlobal) + Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position) + << A.getAttrName()->getName(); + } Prototype.Exit(); @@ -1546,8 +1535,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( TemplateParamScope.Exit(); LambdaScope.Exit(); - if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid()) - return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope()); + if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid() && + !D.isInvalidType()) + return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get()); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); @@ -2353,6 +2343,15 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_bool: DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw__Accum: + DS.SetTypeSpecType(DeclSpec::TST_accum, Loc, PrevSpec, DiagID, Policy); + break; + case tok::kw__Fract: + DS.SetTypeSpecType(DeclSpec::TST_fract, Loc, PrevSpec, DiagID, Policy); + break; + case tok::kw__Sat: + DS.SetTypeSpecSat(Loc, PrevSpec, DiagID); + break; #define GENERIC_IMAGE_TYPE(ImgType, Id) \ case tok::kw_##ImgType##_t: \ DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, DiagID, \ @@ -3114,10 +3113,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, } // Note that this is a destructor name. - ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName, - ClassNameLoc, getCurScope(), - SS, ObjectType, - EnteringContext); + ParsedType Ty = + Actions.getDestructorName(*ClassName, ClassNameLoc, getCurScope(), SS, + ObjectType, EnteringContext); if (!Ty) return true; @@ -3493,11 +3491,11 @@ ExprResult Parser::ParseRequiresExpression() { SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires' llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls; + BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Tok.is(tok::l_paren)) { // requirement parameter list is present. ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope | Scope::DeclScope); - BalancedDelimiterTracker Parens(*this, tok::l_paren); Parens.consumeOpen(); if (!Tok.is(tok::r_paren)) { ParsedAttributes FirstArgAttrs(getAttrFactory()); @@ -3626,10 +3624,12 @@ ExprResult Parser::ParseRequiresExpression() { auto Res = TryParseParameterDeclarationClause(); if (Res != TPResult::False) { // Skip to the closing parenthesis - // FIXME: Don't traverse these tokens twice (here and in - // TryParseParameterDeclarationClause). unsigned Depth = 1; while (Depth != 0) { + bool FoundParen = SkipUntil(tok::l_paren, tok::r_paren, + SkipUntilFlags::StopBeforeMatch); + if (!FoundParen) + break; if (Tok.is(tok::l_paren)) Depth++; else if (Tok.is(tok::r_paren)) @@ -3769,8 +3769,9 @@ ExprResult Parser::ParseRequiresExpression() { Braces.consumeClose(); Actions.ActOnFinishRequiresExpr(); ParsingBodyDecl.complete(Body); - return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls, - Requirements, Braces.getCloseLocation()); + return Actions.ActOnRequiresExpr( + RequiresKWLoc, Body, Parens.getOpenLocation(), LocalParameterDecls, + Parens.getCloseLocation(), Requirements, Braces.getCloseLocation()); } static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { diff --git a/contrib/llvm-project/clang/lib/Parse/ParseInit.cpp b/contrib/llvm-project/clang/lib/Parse/ParseInit.cpp index f52c04ba2c4d..637f21176792 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseInit.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseInit.cpp @@ -431,7 +431,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator( /// initializer: [C99 6.7.8] /// '{' initializer-list '}' /// '{' initializer-list ',' '}' -/// [C2x] '{' '}' +/// [C23] '{' '}' /// /// initializer-list: /// designation[opt] initializer ...[opt] @@ -449,10 +449,10 @@ ExprResult Parser::ParseBraceInitializer() { ExprVector InitExprs; if (Tok.is(tok::r_brace)) { - // Empty initializers are a C++ feature and a GNU extension to C before C2x. + // Empty initializers are a C++ feature and a GNU extension to C before C23. if (!getLangOpts().CPlusPlus) { - Diag(LBraceLoc, getLangOpts().C2x - ? diag::warn_c2x_compat_empty_initializer + Diag(LBraceLoc, getLangOpts().C23 + ? diag::warn_c23_compat_empty_initializer : diag::ext_c_empty_initializer); } // Match the '}'. diff --git a/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp index b30f0380621a..c0261c462b88 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp @@ -65,10 +65,10 @@ Parser::ParseObjCAtDirectives(ParsedAttributes &DeclAttrs, case tok::objc_implementation: break; default: - llvm::for_each(DeclAttrs, [this](const auto &Attr) { + for (const auto &Attr : DeclAttrs) { if (Attr.isGNUAttribute()) Diag(Tok.getLocation(), diag::err_objc_unexpected_attr); - }); + } } Decl *SingleDecl = nullptr; @@ -613,6 +613,19 @@ ObjCTypeParamList *Parser::parseObjCTypeParamList() { /*mayBeProtocolList=*/false); } +static bool isTopLevelObjCKeyword(tok::ObjCKeywordKind DirectiveKind) { + switch (DirectiveKind) { + case tok::objc_class: + case tok::objc_compatibility_alias: + case tok::objc_interface: + case tok::objc_implementation: + case tok::objc_protocol: + return true; + default: + return false; + } +} + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -705,27 +718,34 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, continue; } - // Otherwise, we have an @ directive, eat the @. - SourceLocation AtLoc = ConsumeToken(); // the "@" - if (Tok.is(tok::code_completion)) { + // Otherwise, we have an @ directive, peak at the next token + SourceLocation AtLoc = Tok.getLocation(); + const auto &NextTok = NextToken(); + if (NextTok.is(tok::code_completion)) { cutOffParsing(); Actions.CodeCompleteObjCAtDirective(getCurScope()); return; } - tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); - + tok::ObjCKeywordKind DirectiveKind = NextTok.getObjCKeywordID(); if (DirectiveKind == tok::objc_end) { // @end -> terminate list + ConsumeToken(); // the "@" AtEnd.setBegin(AtLoc); AtEnd.setEnd(Tok.getLocation()); break; } else if (DirectiveKind == tok::objc_not_keyword) { - Diag(Tok, diag::err_objc_unknown_at); + Diag(NextTok, diag::err_objc_unknown_at); SkipUntil(tok::semi); continue; } - // Eat the identifier. + // If we see something like '@interface' that's only allowed at the top + // level, bail out as if we saw an '@end'. We'll diagnose this below. + if (isTopLevelObjCKeyword(DirectiveKind)) + break; + + // Otherwise parse it as part of the current declaration. Eat "@identifier". + ConsumeToken(); ConsumeToken(); switch (DirectiveKind) { @@ -739,15 +759,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, SkipUntil(tok::r_brace, tok::at, StopAtSemi); break; - case tok::objc_implementation: - case tok::objc_interface: - Diag(AtLoc, diag::err_objc_missing_end) - << FixItHint::CreateInsertion(AtLoc, "@end\n"); - Diag(CDecl->getBeginLoc(), diag::note_objc_container_start) - << (int)Actions.getObjCContainerKind(); - ConsumeToken(); - break; - case tok::objc_required: case tok::objc_optional: // This is only valid on protocols. @@ -816,13 +827,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, } } - // We break out of the big loop in two cases: when we see @end or when we see - // EOF. In the former case, eat the @end. In the later case, emit an error. - if (Tok.is(tok::code_completion)) { - cutOffParsing(); - Actions.CodeCompleteObjCAtDirective(getCurScope()); - return; - } else if (Tok.isObjCAtKeyword(tok::objc_end)) { + // We break out of the big loop in 3 cases: when we see @end or when we see + // top-level ObjC keyword or EOF. In the former case, eat the @end. In the + // later cases, emit an error. + if (Tok.isObjCAtKeyword(tok::objc_end)) { ConsumeToken(); // the "end" identifier } else { Diag(Tok, diag::err_objc_missing_end) @@ -3756,6 +3764,8 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } - // Clean up the remaining EOF token. - ConsumeAnyToken(); + // Clean up the remaining EOF token, only if it's inserted by us. Otherwise + // this might be code-completion token, which must be propagated to callers. + if (Tok.is(tok::eof) && Tok.getEofData() == MCDecl) + ConsumeAnyToken(); } diff --git a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp new file mode 100644 index 000000000000..f7f096762e91 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp @@ -0,0 +1,527 @@ +//===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the parsing logic for OpenACC language features. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OpenACCKinds.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Parse/RAIIObjectsForParser.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace llvm; + +namespace { +// An enum that contains the extended 'partial' parsed variants. This type +// should never escape the initial parse functionality, but is useful for +// simplifying the implementation. +enum class OpenACCDirectiveKindEx { + Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid), + // 'enter data' and 'exit data' + Enter, + Exit, +}; + +// Translate single-token string representations to the OpenACC Directive Kind. +// This doesn't completely comprehend 'Compound Constructs' (as it just +// identifies the first token), and doesn't fully handle 'enter data', 'exit +// data', nor any of the 'atomic' variants, just the first token of each. So +// this should only be used by `ParseOpenACCDirectiveKind`. +OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) { + if (!Tok.is(tok::identifier)) + return OpenACCDirectiveKindEx::Invalid; + OpenACCDirectiveKind DirKind = + llvm::StringSwitch<OpenACCDirectiveKind>( + Tok.getIdentifierInfo()->getName()) + .Case("parallel", OpenACCDirectiveKind::Parallel) + .Case("serial", OpenACCDirectiveKind::Serial) + .Case("kernels", OpenACCDirectiveKind::Kernels) + .Case("data", OpenACCDirectiveKind::Data) + .Case("host_data", OpenACCDirectiveKind::HostData) + .Case("loop", OpenACCDirectiveKind::Loop) + .Case("cache", OpenACCDirectiveKind::Cache) + .Case("atomic", OpenACCDirectiveKind::Atomic) + .Case("routine", OpenACCDirectiveKind::Routine) + .Case("declare", OpenACCDirectiveKind::Declare) + .Case("init", OpenACCDirectiveKind::Init) + .Case("shutdown", OpenACCDirectiveKind::Shutdown) + .Case("set", OpenACCDirectiveKind::Shutdown) + .Case("update", OpenACCDirectiveKind::Update) + .Case("wait", OpenACCDirectiveKind::Wait) + .Default(OpenACCDirectiveKind::Invalid); + + if (DirKind != OpenACCDirectiveKind::Invalid) + return static_cast<OpenACCDirectiveKindEx>(DirKind); + + return llvm::StringSwitch<OpenACCDirectiveKindEx>( + Tok.getIdentifierInfo()->getName()) + .Case("enter", OpenACCDirectiveKindEx::Enter) + .Case("exit", OpenACCDirectiveKindEx::Exit) + .Default(OpenACCDirectiveKindEx::Invalid); +} + +// Since 'atomic' is effectively a compound directive, this will decode the +// second part of the directive. +OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) { + if (!Tok.is(tok::identifier)) + return OpenACCAtomicKind::Invalid; + return llvm::StringSwitch<OpenACCAtomicKind>( + Tok.getIdentifierInfo()->getName()) + .Case("read", OpenACCAtomicKind::Read) + .Case("write", OpenACCAtomicKind::Write) + .Case("update", OpenACCAtomicKind::Update) + .Case("capture", OpenACCAtomicKind::Capture) + .Default(OpenACCAtomicKind::Invalid); +} + +enum class OpenACCSpecialTokenKind { + ReadOnly, + DevNum, + Queues, +}; + +bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) { + if (!Tok.is(tok::identifier)) + return false; + + switch (Kind) { + case OpenACCSpecialTokenKind::ReadOnly: + return Tok.getIdentifierInfo()->isStr("readonly"); + case OpenACCSpecialTokenKind::DevNum: + return Tok.getIdentifierInfo()->isStr("devnum"); + case OpenACCSpecialTokenKind::Queues: + return Tok.getIdentifierInfo()->isStr("queues"); + } + llvm_unreachable("Unknown 'Kind' Passed"); +} + +bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { + if (!Tok.is(tok::identifier)) + return false; + + switch (Kind) { + case OpenACCDirectiveKind::Parallel: + return Tok.getIdentifierInfo()->isStr("parallel"); + case OpenACCDirectiveKind::Serial: + return Tok.getIdentifierInfo()->isStr("serial"); + case OpenACCDirectiveKind::Kernels: + return Tok.getIdentifierInfo()->isStr("kernels"); + case OpenACCDirectiveKind::Data: + return Tok.getIdentifierInfo()->isStr("data"); + case OpenACCDirectiveKind::HostData: + return Tok.getIdentifierInfo()->isStr("host_data"); + case OpenACCDirectiveKind::Loop: + return Tok.getIdentifierInfo()->isStr("loop"); + case OpenACCDirectiveKind::Cache: + return Tok.getIdentifierInfo()->isStr("cache"); + + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + return false; + + case OpenACCDirectiveKind::Atomic: + return Tok.getIdentifierInfo()->isStr("atomic"); + case OpenACCDirectiveKind::Routine: + return Tok.getIdentifierInfo()->isStr("routine"); + case OpenACCDirectiveKind::Declare: + return Tok.getIdentifierInfo()->isStr("declare"); + case OpenACCDirectiveKind::Init: + return Tok.getIdentifierInfo()->isStr("init"); + case OpenACCDirectiveKind::Shutdown: + return Tok.getIdentifierInfo()->isStr("shutdown"); + case OpenACCDirectiveKind::Set: + return Tok.getIdentifierInfo()->isStr("set"); + case OpenACCDirectiveKind::Update: + return Tok.getIdentifierInfo()->isStr("update"); + case OpenACCDirectiveKind::Wait: + return Tok.getIdentifierInfo()->isStr("wait"); + case OpenACCDirectiveKind::Invalid: + return false; + } + llvm_unreachable("Unknown 'Kind' Passed"); +} + +OpenACCDirectiveKind +ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, + OpenACCDirectiveKindEx ExtDirKind) { + Token SecondTok = P.getCurToken(); + + if (SecondTok.isAnnotation()) { + P.Diag(FirstTok, diag::err_acc_invalid_directive) + << 0 << FirstTok.getIdentifierInfo(); + return OpenACCDirectiveKind::Invalid; + } + + if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) { + if (!SecondTok.is(tok::identifier)) + P.Diag(SecondTok, diag::err_expected) << tok::identifier; + else + P.Diag(FirstTok, diag::err_acc_invalid_directive) + << 1 << FirstTok.getIdentifierInfo()->getName() + << SecondTok.getIdentifierInfo()->getName(); + return OpenACCDirectiveKind::Invalid; + } + + P.ConsumeToken(); + + return ExtDirKind == OpenACCDirectiveKindEx::Enter + ? OpenACCDirectiveKind::EnterData + : OpenACCDirectiveKind::ExitData; +} + +OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) { + Token AtomicClauseToken = P.getCurToken(); + + // #pragma acc atomic is equivilent to update: + if (AtomicClauseToken.isAnnotation()) + return OpenACCAtomicKind::Update; + + OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken); + + // If we don't know what this is, treat it as 'nothing', and treat the rest of + // this as a clause list, which, despite being invalid, is likely what the + // user was trying to do. + if (AtomicKind == OpenACCAtomicKind::Invalid) + return OpenACCAtomicKind::Update; + + P.ConsumeToken(); + return AtomicKind; +} + +// Parse and consume the tokens for OpenACC Directive/Construct kinds. +OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { + Token FirstTok = P.getCurToken(); + + // Just #pragma acc can get us immediately to the end, make sure we don't + // introspect on the spelling before then. + if (FirstTok.isNot(tok::identifier)) { + P.Diag(FirstTok, diag::err_acc_missing_directive); + return OpenACCDirectiveKind::Invalid; + } + + P.ConsumeToken(); + + OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok); + + // OpenACCDirectiveKindEx is meant to be an extended list + // over OpenACCDirectiveKind, so any value below Invalid is one of the + // OpenACCDirectiveKind values. This switch takes care of all of the extra + // parsing required for the Extended values. At the end of this block, + // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can + // immediately cast it and use it as that. + if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) { + switch (ExDirKind) { + case OpenACCDirectiveKindEx::Invalid: { + P.Diag(FirstTok, diag::err_acc_invalid_directive) + << 0 << FirstTok.getIdentifierInfo(); + return OpenACCDirectiveKind::Invalid; + } + case OpenACCDirectiveKindEx::Enter: + case OpenACCDirectiveKindEx::Exit: + return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind); + } + } + + OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind); + + // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any + // other attempt at a combined construct will be diagnosed as an invalid + // clause. + Token SecondTok = P.getCurToken(); + if (!SecondTok.isAnnotation() && + isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) { + switch (DirKind) { + default: + // Nothing to do except in the below cases, as they should be diagnosed as + // a clause. + break; + case OpenACCDirectiveKind::Parallel: + P.ConsumeToken(); + return OpenACCDirectiveKind::ParallelLoop; + case OpenACCDirectiveKind::Serial: + P.ConsumeToken(); + return OpenACCDirectiveKind::SerialLoop; + case OpenACCDirectiveKind::Kernels: + P.ConsumeToken(); + return OpenACCDirectiveKind::KernelsLoop; + } + } + + return DirKind; +} + +void ParseOpenACCClauseList(Parser &P) { + // FIXME: In the future, we'll start parsing the clauses here, but for now we + // haven't implemented that, so just emit the unimplemented diagnostic and + // fail reasonably. + if (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) + P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing); +} + +} // namespace + +/// OpenACC 3.3, section 2.16: +/// In this section and throughout the specification, the term wait-argument +/// means: +/// [ devnum : int-expr : ] [ queues : ] async-argument-list +bool Parser::ParseOpenACCWaitArgument() { + // [devnum : int-expr : ] + if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) && + NextToken().is(tok::colon)) { + // Consume devnum. + ConsumeToken(); + // Consume colon. + ConsumeToken(); + + ExprResult IntExpr = + getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + if (IntExpr.isInvalid()) + return true; + + if (ExpectAndConsume(tok::colon)) + return true; + } + + // [ queues : ] + if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) && + NextToken().is(tok::colon)) { + // Consume queues. + ConsumeToken(); + // Consume colon. + ConsumeToken(); + } + + // OpenACC 3.3, section 2.16: + // the term 'async-argument' means a nonnegative scalar integer expression, or + // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined + // in the C header file and the Fortran opacc module. + // + // We are parsing this simply as list of assignment expressions (to avoid + // comma being troublesome), and will ensure it is an integral type. The + // 'special' types are defined as macros, so we can't really check those + // (other than perhaps as values at one point?), but the standard does say it + // is implementation-defined to use any other negative value. + // + // + bool FirstArg = true; + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { + if (!FirstArg) { + if (ExpectAndConsume(tok::comma)) + return true; + } + FirstArg = false; + + ExprResult CurArg = + getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + + if (CurArg.isInvalid()) + return true; + } + + return false; +} + +ExprResult Parser::ParseOpenACCIDExpression() { + ExprResult Res; + if (getLangOpts().CPlusPlus) { + Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false); + } else { + // There isn't anything quite the same as ParseCXXIdExpression for C, so we + // need to get the identifier, then call into Sema ourselves. + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected) << tok::identifier; + return ExprError(); + } + + Token FuncName = getCurToken(); + UnqualifiedId Name; + CXXScopeSpec ScopeSpec; + SourceLocation TemplateKWLoc; + Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken()); + + // Ensure this is a valid identifier. We don't accept causing implicit + // function declarations per the spec, so always claim to not have trailing + // L Paren. + Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc, + Name, /*HasTrailingLParen=*/false, + /*isAddressOfOperand=*/false); + } + + return getActions().CorrectDelayedTyposInExpr(Res); +} + +/// OpenACC 3.3, section 2.10: +/// A 'var' in a cache directive must be a single array element or a simple +/// subarray. In C and C++, a simple subarray is an array name followed by an +/// extended array range specification in brackets, with a start and length such +/// as: +/// +/// arr[lower:length] +/// +bool Parser::ParseOpenACCCacheVar() { + ExprResult ArrayName = ParseOpenACCIDExpression(); + if (ArrayName.isInvalid()) + return true; + + // If the expression is invalid, just continue parsing the brackets, there + // is likely other useful diagnostics we can emit inside of those. + + BalancedDelimiterTracker SquareBrackets(*this, tok::l_square, + tok::annot_pragma_openacc_end); + + // Square brackets are required, so error here, and try to recover by moving + // until the next comma, or the close paren/end of pragma. + if (SquareBrackets.expectAndConsume()) { + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, + Parser::StopBeforeMatch); + return true; + } + + ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression()); + if (Lower.isInvalid()) + return true; + + // The 'length' expression is optional, as this could be a single array + // element. If there is no colon, we can treat it as that. + if (getCurToken().is(tok::colon)) { + ConsumeToken(); + ExprResult Length = + getActions().CorrectDelayedTyposInExpr(ParseExpression()); + if (Length.isInvalid()) + return true; + } + + // Diagnose the square bracket being in the wrong place and continue. + return SquareBrackets.consumeClose(); +} + +/// OpenACC 3.3, section 2.10: +/// In C and C++, the syntax of the cache directive is: +/// +/// #pragma acc cache ([readonly:]var-list) new-line +void Parser::ParseOpenACCCacheVarList() { + // If this is the end of the line, just return 'false' and count on the close + // paren diagnostic to catch the issue. + if (getCurToken().isAnnotation()) + return; + + // The VarList is an optional `readonly:` followed by a list of a variable + // specifications. First, see if we have `readonly:`, else we back-out and + // treat it like the beginning of a reference to a potentially-existing + // `readonly` variable. + if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) && + NextToken().is(tok::colon)) { + // Consume both tokens. + ConsumeToken(); + ConsumeToken(); + // FIXME: Record that this is a 'readonly' so that we can use that during + // Sema/AST generation. + } + + bool FirstArray = true; + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { + if (!FirstArray) + ExpectAndConsume(tok::comma); + FirstArray = false; + if (ParseOpenACCCacheVar()) + SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma, + StopBeforeMatch); + } +} + +void Parser::ParseOpenACCDirective() { + OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); + + // Once we've parsed the construct/directive name, some have additional + // specifiers that need to be taken care of. Atomic has an 'atomic-clause' + // that needs to be parsed. + if (DirKind == OpenACCDirectiveKind::Atomic) + ParseOpenACCAtomicKind(*this); + + // We've successfully parsed the construct/directive name, however a few of + // the constructs have optional parens that contain further details. + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openacc_end); + + if (!T.consumeOpen()) { + switch (DirKind) { + default: + Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren); + T.skipToEnd(); + break; + case OpenACCDirectiveKind::Routine: { + // Routine has an optional paren-wrapped name of a function in the local + // scope. We parse the name, emitting any diagnostics + ExprResult RoutineName = ParseOpenACCIDExpression(); + // If the routine name is invalid, just skip until the closing paren to + // recover more gracefully. + if (RoutineName.isInvalid()) + T.skipToEnd(); + else + T.consumeClose(); + break; + } + case OpenACCDirectiveKind::Cache: + ParseOpenACCCacheVarList(); + // The ParseOpenACCCacheVarList function manages to recover from failures, + // so we can always consume the close. + T.consumeClose(); + break; + case OpenACCDirectiveKind::Wait: + // OpenACC has an optional paren-wrapped 'wait-argument'. + if (ParseOpenACCWaitArgument()) + T.skipToEnd(); + else + T.consumeClose(); + break; + } + } else if (DirKind == OpenACCDirectiveKind::Cache) { + // Cache's paren var-list is required, so error here if it isn't provided. + // We know that the consumeOpen above left the first non-paren here, so + // diagnose, then continue as if it was completely omitted. + Diag(Tok, diag::err_expected) << tok::l_paren; + } + + // Parses the list of clauses, if present. + ParseOpenACCClauseList(*this); + + Diag(getCurToken(), diag::warn_pragma_acc_unimplemented); + SkipUntil(tok::annot_pragma_openacc_end); +} + +// Parse OpenACC directive on a declaration. +Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { + assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); + + ParsingOpenACCDirectiveRAII DirScope(*this); + ConsumeAnnotationToken(); + + ParseOpenACCDirective(); + + return nullptr; +} + +// Parse OpenACC Directive on a Statement. +StmtResult Parser::ParseOpenACCDirectiveStmt() { + assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); + + ParsingOpenACCDirectiveRAII DirScope(*this); + ConsumeAnnotationToken(); + + ParseOpenACCDirective(); + + return StmtEmpty(); +} diff --git a/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp index 96d2e2cede62..da5f6605c6ff 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp @@ -2418,6 +2418,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_distribute_simd: case OMPD_target_parallel_for_simd: case OMPD_target_simd: + case OMPD_scope: case OMPD_teams_distribute: case OMPD_teams_distribute_simd: case OMPD_teams_distribute_parallel_for_simd: @@ -2517,15 +2518,18 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( switch (DKind) { case OMPD_nothing: - if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == - ParsedStmtContext()) - Diag(Tok, diag::err_omp_immediate_directive) - << getOpenMPDirectiveName(DKind) << 0; ConsumeToken(); - skipUntilPragmaOpenMPEnd(DKind); + // If we are parsing the directive within a metadirective, the directive + // ends with a ')'. + if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + else + skipUntilPragmaOpenMPEnd(DKind); if (Tok.is(tok::annot_pragma_openmp_end)) ConsumeAnnotationToken(); - break; + // return an empty statement + return StmtEmpty(); case OMPD_metadirective: { ConsumeToken(); SmallVector<VariantMatchInfo, 4> VMIs; @@ -2669,7 +2673,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } case OMPD_threadprivate: { // FIXME: Should this be permitted in C++? - if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == ParsedStmtContext()) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; @@ -2688,7 +2692,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } case OMPD_allocate: { // FIXME: Should this be permitted in C++? - if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == ParsedStmtContext()) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; @@ -2810,6 +2814,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_target_teams_loop: case OMPD_parallel_loop: case OMPD_target_parallel_loop: + case OMPD_scope: case OMPD_taskloop: case OMPD_taskloop_simd: case OMPD_master_taskloop: @@ -3246,6 +3251,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, else Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); break; + case OMPC_fail: case OMPC_default: case OMPC_proc_bind: case OMPC_atomic_default_mem_order: @@ -3367,6 +3373,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_exclusive: case OMPC_affinity: case OMPC_doacross: + case OMPC_enter: if (getLangOpts().OpenMP >= 52 && DKind == OMPD_ordered && CKind == OMPC_depend) Diag(Tok, diag::warn_omp_depend_in_ordered_deprecated); @@ -3411,6 +3418,20 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); break; + case OMPC_ompx_attribute: + Clause = ParseOpenMPOMPXAttributesClause(WrongDirective); + break; + case OMPC_ompx_bare: + if (WrongDirective) + Diag(Tok, diag::note_ompx_bare_clause) + << getOpenMPClauseName(CKind) << "target teams"; + if (!ErrorFound && !getLangOpts().OpenMPExtensions) { + Diag(Tok, diag::err_omp_unexpected_clause_extension_only) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + ErrorFound = true; + } + Clause = ParseOpenMPClause(CKind, WrongDirective); + break; default: break; } @@ -3691,6 +3712,63 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, llvm_unreachable("Unexpected interop variable clause."); } +OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { + SourceLocation Loc = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(OMPC_ompx_attribute).data())) + return nullptr; + + ParsedAttributes ParsedAttrs(AttrFactory); + ParseAttributes(PAKM_GNU | PAKM_CXX11, ParsedAttrs); + + // Parse ')'. + if (T.consumeClose()) + return nullptr; + + if (ParseOnly) + return nullptr; + + SmallVector<Attr *> Attrs; + for (const ParsedAttr &PA : ParsedAttrs) { + switch (PA.getKind()) { + case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: + if (!PA.checkExactlyNumArgs(Actions, 2)) + continue; + if (auto *A = Actions.CreateAMDGPUFlatWorkGroupSizeAttr( + PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1))) + Attrs.push_back(A); + continue; + case ParsedAttr::AT_AMDGPUWavesPerEU: + if (!PA.checkAtLeastNumArgs(Actions, 1) || + !PA.checkAtMostNumArgs(Actions, 2)) + continue; + if (auto *A = Actions.CreateAMDGPUWavesPerEUAttr( + PA, PA.getArgAsExpr(0), + PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr)) + Attrs.push_back(A); + continue; + case ParsedAttr::AT_CUDALaunchBounds: + if (!PA.checkAtLeastNumArgs(Actions, 1) || + !PA.checkAtMostNumArgs(Actions, 2)) + continue; + if (auto *A = Actions.CreateLaunchBoundsAttr( + PA, PA.getArgAsExpr(0), + PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr, + PA.getNumArgs() > 2 ? PA.getArgAsExpr(2) : nullptr)) + Attrs.push_back(A); + continue; + default: + Diag(Loc, diag::warn_omp_invalid_attribute_for_ompx_attributes) << PA; + continue; + }; + } + + return Actions.ActOnOpenMPXAttributeClause(Attrs, Loc, T.getOpenLocation(), + T.getCloseLocation()); +} + /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: @@ -4125,6 +4203,10 @@ bool Parser::parseMapTypeModifiers(Sema::OpenMPVarListDataTy &Data) { TypeModifier == OMPC_MAP_MODIFIER_ompx_hold) { Data.MapTypeModifiers.push_back(TypeModifier); Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); + if (PP.LookAhead(0).isNot(tok::comma) && + PP.LookAhead(0).isNot(tok::colon) && getLangOpts().OpenMP >= 52) + Diag(Tok.getLocation(), diag::err_omp_missing_comma) + << "map type modifier"; ConsumeToken(); } else if (TypeModifier == OMPC_MAP_MODIFIER_mapper) { Data.MapTypeModifiers.push_back(TypeModifier); @@ -4132,6 +4214,11 @@ bool Parser::parseMapTypeModifiers(Sema::OpenMPVarListDataTy &Data) { ConsumeToken(); if (parseMapperModifier(Data)) return true; + if (Tok.isNot(tok::comma) && Tok.isNot(tok::colon) && + getLangOpts().OpenMP >= 52) + Diag(Data.MapTypeModifiersLoc.back(), diag::err_omp_missing_comma) + << "map type modifier"; + } else { // For the case of unknown map-type-modifier or a map-type. // Map-type is followed by a colon; the function returns when it @@ -4319,6 +4406,25 @@ bool Parser::ParseOpenMPReservedLocator(OpenMPClauseKind Kind, return false; } +/// Parse step size expression. Returns true if parsing is successfull, +/// otherwise returns false. +static bool parseStepSize(Parser &P, Sema::OpenMPVarListDataTy &Data, + OpenMPClauseKind CKind, SourceLocation ELoc) { + ExprResult Tail = P.ParseAssignmentExpression(); + Sema &Actions = P.getActions(); + Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc, + /*DiscardedValue*/ false); + if (Tail.isUsable()) { + Data.DepModOrTailExpr = Tail.get(); + Token CurTok = P.getCurToken(); + if (CurTok.isNot(tok::r_paren) && CurTok.isNot(tok::comma)) { + P.Diag(CurTok, diag::err_expected_punc) << "step expression"; + } + return true; + } + return false; +} + /// Parses clauses with list. bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, @@ -4472,6 +4578,10 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ExtraModifierLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; + if (getLangOpts().OpenMP >= 52) + Diag(Data.ExtraModifierLoc, diag::err_omp_deprecate_old_syntax) + << "linear-modifier(list)" << getOpenMPClauseName(Kind) + << "linear(list: [linear-modifier,] step(step-size))"; } } else if (Kind == OMPC_lastprivate) { // Try to parse modifier if any. @@ -4681,19 +4791,76 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, if (NeedRParenForLinear) LinearT.consumeClose(); - // Parse ':' linear-step (or ':' alignment). + // Parse ':' linear modifiers (val, uval, ref or step(step-size)) + // or parse ':' alignment. const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); + bool StepFound = false; + bool ModifierFound = false; if (MustHaveTail) { Data.ColonLoc = Tok.getLocation(); SourceLocation ELoc = ConsumeToken(); - ExprResult Tail = ParseAssignmentExpression(); - Tail = - Actions.ActOnFinishFullExpr(Tail.get(), ELoc, /*DiscardedValue*/ false); - if (Tail.isUsable()) - Data.DepModOrTailExpr = Tail.get(); - else - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); + + if (getLangOpts().OpenMP >= 52 && Kind == OMPC_linear) { + while (Tok.isNot(tok::r_paren)) { + if (Tok.is(tok::identifier)) { + // identifier could be a linear kind (val, uval, ref) or step + // modifier or step size + OpenMPLinearClauseKind LinKind = + static_cast<OpenMPLinearClauseKind>(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), + getLangOpts())); + + if (LinKind == OMPC_LINEAR_step) { + if (StepFound) + Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 0; + + BalancedDelimiterTracker StepT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + SourceLocation StepModifierLoc = ConsumeToken(); + // parse '(' + if (StepT.consumeOpen()) + Diag(StepModifierLoc, diag::err_expected_lparen_after) << "step"; + + // parse step size expression + StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); + if (StepFound) + Data.StepModifierLoc = StepModifierLoc; + + // parse ')' + StepT.consumeClose(); + } else if (LinKind >= 0 && LinKind < OMPC_LINEAR_step) { + if (ModifierFound) + Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 1; + + Data.ExtraModifier = LinKind; + Data.ExtraModifierLoc = ConsumeToken(); + ModifierFound = true; + } else { + StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); + } + } else { + // parse an integer expression as step size + StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); + } + + if (Tok.is(tok::comma)) + ConsumeToken(); + if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end)) + break; + } + if (!StepFound && !ModifierFound) + Diag(ELoc, diag::err_expected_expression); + } else { + // for OMPC_aligned and OMPC_linear (with OpenMP <= 5.1) + ExprResult Tail = ParseAssignmentExpression(); + Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc, + /*DiscardedValue*/ false); + if (Tail.isUsable()) + Data.DepModOrTailExpr = Tail.get(); + else + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } } // Parse ')'. @@ -4705,8 +4872,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, ExitScope(); return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map && Vars.empty()) || - (MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId || - IsInvalidMapperModifier || InvalidIterator; + (MustHaveTail && !Data.DepModOrTailExpr && StepFound) || + InvalidReductionId || IsInvalidMapperModifier || InvalidIterator; } /// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', diff --git a/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp index b3178aef64d7..730ac1a0fee5 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp @@ -137,7 +137,20 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { tok::OnOffSwitch OOS; - PP.LexOnOffSwitch(OOS); + if (PP.LexOnOffSwitch(OOS)) + return; + + MutableArrayRef<Token> Toks( + PP.getPreprocessorAllocator().Allocate<Token>(1), 1); + + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_cx_limited_range); + Toks[0].setLocation(Tok.getLocation()); + Toks[0].setAnnotationEndLoc(Tok.getLocation()); + Toks[0].setAnnotationValue( + reinterpret_cast<void *>(static_cast<uintptr_t>(OOS))); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } }; @@ -166,18 +179,51 @@ struct PragmaFPHandler : public PragmaHandler { Token &FirstToken) override; }; -struct PragmaNoOpenMPHandler : public PragmaHandler { - PragmaNoOpenMPHandler() : PragmaHandler("omp") { } +// A pragma handler to be the base of the NoOpenMPHandler and NoOpenACCHandler, +// which are identical other than the name given to them, and the diagnostic +// emitted. +template <diag::kind IgnoredDiag> +struct PragmaNoSupportHandler : public PragmaHandler { + PragmaNoSupportHandler(StringRef Name) : PragmaHandler(Name) {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; -struct PragmaOpenMPHandler : public PragmaHandler { - PragmaOpenMPHandler() : PragmaHandler("omp") { } +struct PragmaNoOpenMPHandler + : public PragmaNoSupportHandler<diag::warn_pragma_omp_ignored> { + PragmaNoOpenMPHandler() : PragmaNoSupportHandler("omp") {} +}; + +struct PragmaNoOpenACCHandler + : public PragmaNoSupportHandler<diag::warn_pragma_acc_ignored> { + PragmaNoOpenACCHandler() : PragmaNoSupportHandler("acc") {} +}; + +// A pragma handler to be the base for the OpenMPHandler and OpenACCHandler, +// which are identical other than the tokens used for the start/end of a pragma +// section, and some diagnostics. +template <tok::TokenKind StartTok, tok::TokenKind EndTok, + diag::kind UnexpectedDiag> +struct PragmaSupportHandler : public PragmaHandler { + PragmaSupportHandler(StringRef Name) : PragmaHandler(Name) {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; +struct PragmaOpenMPHandler + : public PragmaSupportHandler<tok::annot_pragma_openmp, + tok::annot_pragma_openmp_end, + diag::err_omp_unexpected_directive> { + PragmaOpenMPHandler() : PragmaSupportHandler("omp") {} +}; + +struct PragmaOpenACCHandler + : public PragmaSupportHandler<tok::annot_pragma_openacc, + tok::annot_pragma_openacc_end, + diag::err_acc_unexpected_directive> { + PragmaOpenACCHandler() : PragmaSupportHandler("acc") {} +}; + /// PragmaCommentHandler - "\#pragma comment ...". struct PragmaCommentHandler : public PragmaHandler { PragmaCommentHandler(Sema &Actions) @@ -423,6 +469,12 @@ void Parser::initializePragmaHandlers() { OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>(); PP.AddPragmaHandler(OpenMPHandler.get()); + if (getLangOpts().OpenACC) + OpenACCHandler = std::make_unique<PragmaOpenACCHandler>(); + else + OpenACCHandler = std::make_unique<PragmaNoOpenACCHandler>(); + PP.AddPragmaHandler(OpenACCHandler.get()); + if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isOSBinFormatELF()) { MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions); @@ -542,6 +594,9 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler(OpenMPHandler.get()); OpenMPHandler.reset(); + PP.RemovePragmaHandler(OpenACCHandler.get()); + OpenACCHandler.reset(); + if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isOSBinFormatELF()) { PP.RemovePragmaHandler(MSCommentHandler.get()); @@ -846,6 +901,31 @@ void Parser::HandlePragmaFEnvRound() { Actions.ActOnPragmaFEnvRound(PragmaLoc, RM); } +void Parser::HandlePragmaCXLimitedRange() { + assert(Tok.is(tok::annot_pragma_cx_limited_range)); + tok::OnOffSwitch OOS = static_cast<tok::OnOffSwitch>( + reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + + LangOptions::ComplexRangeKind Range; + switch (OOS) { + case tok::OOS_ON: + Range = LangOptions::CX_Limited; + break; + case tok::OOS_OFF: + Range = LangOptions::CX_Full; + break; + case tok::OOS_DEFAULT: + // According to ISO C99 standard chapter 7.3.4, the default value + // for the pragma is ``off'. -fcx-limited-range and -fcx-fortran-rules + // control the default value of these pragmas. + Range = getLangOpts().getComplexRange(); + break; + } + + SourceLocation PragmaLoc = ConsumeAnnotationToken(); + Actions.ActOnPragmaCXLimitedRange(PragmaLoc, Range); +} + StmtResult Parser::HandlePragmaCaptured() { assert(Tok.is(tok::annot_pragma_captured)); @@ -2610,42 +2690,42 @@ void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, StateLoc, State); } -/// Handle '#pragma omp ...' when OpenMP is disabled. -/// -void PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducer Introducer, - Token &FirstTok) { - if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored, - FirstTok.getLocation())) { - PP.Diag(FirstTok, diag::warn_pragma_omp_ignored); - PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored, - diag::Severity::Ignored, SourceLocation()); +/// Handle '#pragma omp ...' when OpenMP is disabled and '#pragma acc ...' when +/// OpenACC is disabled. +template <diag::kind IgnoredDiag> +void PragmaNoSupportHandler<IgnoredDiag>::HandlePragma( + Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstTok) { + if (!PP.getDiagnostics().isIgnored(IgnoredDiag, FirstTok.getLocation())) { + PP.Diag(FirstTok, IgnoredDiag); + PP.getDiagnostics().setSeverity(IgnoredDiag, diag::Severity::Ignored, + SourceLocation()); } PP.DiscardUntilEndOfDirective(); } -/// Handle '#pragma omp ...' when OpenMP is enabled. -/// -void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducer Introducer, - Token &FirstTok) { +/// Handle '#pragma omp ...' when OpenMP is enabled, and handle '#pragma acc...' +/// when OpenACC is enabled. +template <tok::TokenKind StartTok, tok::TokenKind EndTok, + diag::kind UnexpectedDiag> +void PragmaSupportHandler<StartTok, EndTok, UnexpectedDiag>::HandlePragma( + Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstTok) { SmallVector<Token, 16> Pragma; Token Tok; Tok.startToken(); - Tok.setKind(tok::annot_pragma_openmp); + Tok.setKind(StartTok); Tok.setLocation(Introducer.Loc); while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) { Pragma.push_back(Tok); PP.Lex(Tok); - if (Tok.is(tok::annot_pragma_openmp)) { - PP.Diag(Tok, diag::err_omp_unexpected_directive) << 0; + if (Tok.is(StartTok)) { + PP.Diag(Tok, UnexpectedDiag) << 0; unsigned InnerPragmaCnt = 1; while (InnerPragmaCnt != 0) { PP.Lex(Tok); - if (Tok.is(tok::annot_pragma_openmp)) + if (Tok.is(StartTok)) ++InnerPragmaCnt; - else if (Tok.is(tok::annot_pragma_openmp_end)) + else if (Tok.is(EndTok)) --InnerPragmaCnt; } PP.Lex(Tok); @@ -2653,7 +2733,7 @@ void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, } SourceLocation EodLoc = Tok.getLocation(); Tok.startToken(); - Tok.setKind(tok::annot_pragma_openmp_end); + Tok.setKind(EndTok); Tok.setLocation(EodLoc); Pragma.push_back(Tok); @@ -3191,11 +3271,11 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, namespace { /// Used as the annotation value for tok::annot_pragma_fp. struct TokFPAnnotValue { - enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod }; enum FlagValues { On, Off, Fast }; std::optional<LangOptions::FPModeKind> ContractValue; std::optional<LangOptions::FPModeKind> ReassociateValue; + std::optional<LangOptions::FPModeKind> ReciprocalValue; std::optional<LangOptions::FPExceptionModeKind> ExceptionsValue; std::optional<LangOptions::FPEvalMethodKind> EvalMethodValue; }; @@ -3219,12 +3299,12 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); auto FlagKind = - llvm::StringSwitch<std::optional<TokFPAnnotValue::FlagKinds>>( - OptionInfo->getName()) - .Case("contract", TokFPAnnotValue::Contract) - .Case("reassociate", TokFPAnnotValue::Reassociate) - .Case("exceptions", TokFPAnnotValue::Exceptions) - .Case("eval_method", TokFPAnnotValue::EvalMethod) + llvm::StringSwitch<std::optional<PragmaFPKind>>(OptionInfo->getName()) + .Case("contract", PFK_Contract) + .Case("reassociate", PFK_Reassociate) + .Case("exceptions", PFK_Exceptions) + .Case("eval_method", PFK_EvalMethod) + .Case("reciprocal", PFK_Reciprocal) .Default(std::nullopt); if (!FlagKind) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) @@ -3240,7 +3320,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, } PP.Lex(Tok); bool isEvalMethodDouble = - Tok.is(tok::kw_double) && FlagKind == TokFPAnnotValue::EvalMethod; + Tok.is(tok::kw_double) && FlagKind == PFK_EvalMethod; // Don't diagnose if we have an eval_metod pragma with "double" kind. if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) { @@ -3251,7 +3331,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, } const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (FlagKind == TokFPAnnotValue::Contract) { + if (FlagKind == PFK_Contract) { AnnotValue->ContractValue = llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>( II->getName()) @@ -3264,19 +3344,20 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; return; } - } else if (FlagKind == TokFPAnnotValue::Reassociate) { - AnnotValue->ReassociateValue = - llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>( - II->getName()) - .Case("on", LangOptions::FPModeKind::FPM_On) - .Case("off", LangOptions::FPModeKind::FPM_Off) - .Default(std::nullopt); - if (!AnnotValue->ReassociateValue) { + } else if (FlagKind == PFK_Reassociate || FlagKind == PFK_Reciprocal) { + auto &Value = FlagKind == PFK_Reassociate ? AnnotValue->ReassociateValue + : AnnotValue->ReciprocalValue; + Value = llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>( + II->getName()) + .Case("on", LangOptions::FPModeKind::FPM_On) + .Case("off", LangOptions::FPModeKind::FPM_Off) + .Default(std::nullopt); + if (!Value) { PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; return; } - } else if (FlagKind == TokFPAnnotValue::Exceptions) { + } else if (FlagKind == PFK_Exceptions) { AnnotValue->ExceptionsValue = llvm::StringSwitch<std::optional<LangOptions::FPExceptionModeKind>>( II->getName()) @@ -3289,7 +3370,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; return; } - } else if (FlagKind == TokFPAnnotValue::EvalMethod) { + } else if (FlagKind == PFK_EvalMethod) { AnnotValue->EvalMethodValue = llvm::StringSwitch<std::optional<LangOptions::FPEvalMethodKind>>( II->getName()) @@ -3395,9 +3476,15 @@ void Parser::HandlePragmaFP() { reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue()); if (AnnotValue->ReassociateValue) - Actions.ActOnPragmaFPReassociate(Tok.getLocation(), - *AnnotValue->ReassociateValue == - LangOptions::FPModeKind::FPM_On); + Actions.ActOnPragmaFPValueChangingOption( + Tok.getLocation(), PFK_Reassociate, + *AnnotValue->ReassociateValue == LangOptions::FPModeKind::FPM_On); + + if (AnnotValue->ReciprocalValue) + Actions.ActOnPragmaFPValueChangingOption( + Tok.getLocation(), PFK_Reciprocal, + *AnnotValue->ReciprocalValue == LangOptions::FPModeKind::FPM_On); + if (AnnotValue->ContractValue) Actions.ActOnPragmaFPContract(Tok.getLocation(), *AnnotValue->ContractValue); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp index 2346470dbdb7..d0ff33bd1379 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp @@ -14,6 +14,7 @@ #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/Parser.h" @@ -234,10 +235,7 @@ Retry: auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) && llvm::all_of(GNUAttrs, IsStmtAttr); - if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || - (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != - ParsedStmtContext()) && - ((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || + if (((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; @@ -446,6 +444,14 @@ Retry: ConsumeAnnotationToken(); return StmtError(); + case tok::annot_pragma_cx_limited_range: + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + Diag(Tok, diag::err_pragma_file_or_compound_scope) + << "STDC CX_LIMITED_RANGE"; + ConsumeAnnotationToken(); + return StmtError(); + case tok::annot_pragma_float_control: ProhibitAttributes(CXX11Attrs); ProhibitAttributes(GNUAttrs); @@ -474,6 +480,9 @@ Retry: // Do not prohibit attributes if they were OpenMP attributes. return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); + case tok::annot_pragma_openacc: + return ParseOpenACCDirectiveStmt(); + case tok::annot_pragma_ms_pointers_to_members: ProhibitAttributes(CXX11Attrs); ProhibitAttributes(GNUAttrs); @@ -697,6 +706,18 @@ StmtResult Parser::ParseSEHLeaveStatement() { return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope()); } +static void DiagnoseLabelFollowedByDecl(Parser &P, const Stmt *SubStmt) { + // When in C mode (but not Microsoft extensions mode), diagnose use of a + // label that is followed by a declaration rather than a statement. + if (!P.getLangOpts().CPlusPlus && !P.getLangOpts().MicrosoftExt && + isa<DeclStmt>(SubStmt)) { + P.Diag(SubStmt->getBeginLoc(), + P.getLangOpts().C23 + ? diag::warn_c23_compat_label_followed_by_declaration + : diag::ext_c_label_followed_by_declaration); + } +} + /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// label: @@ -711,9 +732,10 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs, assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); - // The substatement is always a 'statement', not a 'declaration', but is - // otherwise in the same context as the labeled-statement. - StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a + // substatement in a selection statement, in place of the loop body in an + // iteration statement, or in place of the statement that follows a label. + StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. @@ -762,6 +784,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs, if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); + DiagnoseLabelFollowedByDecl(*this, SubStmt.get()); + LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); @@ -780,9 +804,10 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, bool MissingCase, ExprResult Expr) { assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); - // The substatement is always a 'statement', not a 'declaration', but is - // otherwise in the same context as the labeled-statement. - StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a + // substatement in a selection statement, in place of the loop body in an + // iteration statement, or in place of the statement that follows a label. + StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; // It is very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -908,6 +933,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, // Broken sub-stmt shouldn't prevent forming the case statement properly. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(SourceLocation()); + DiagnoseLabelFollowedByDecl(*this, SubStmt.get()); Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get()); } @@ -923,9 +949,10 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); - // The substatement is always a 'statement', not a 'declaration', but is - // otherwise in the same context as the labeled-statement. - StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a + // substatement in a selection statement, in place of the loop body in an + // iteration statement, or in place of the statement that follows a label. + StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -959,6 +986,7 @@ StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); + DiagnoseLabelFollowedByDecl(*this, SubStmt.get()); return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt.get(), getCurScope()); } @@ -1046,6 +1074,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() { case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); break; + case tok::annot_pragma_cx_limited_range: + HandlePragmaCXLimitedRange(); + break; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); break; @@ -1075,8 +1106,8 @@ void Parser::DiagnoseLabelAtEndOfCompoundStatement() { ? diag::warn_cxx20_compat_label_end_of_compound_statement : diag::ext_cxx_label_end_of_compound_statement); } else { - Diag(Tok, getLangOpts().C2x - ? diag::warn_c2x_compat_label_end_of_compound_statement + Diag(Tok, getLangOpts().C23 + ? diag::warn_c23_compat_label_end_of_compound_statement : diag::ext_c_label_end_of_compound_statement); } } @@ -1894,7 +1925,8 @@ StmtResult Parser::ParseDoStatement() { ExprResult Cond = ParseExpression(); // Correct the typos in condition before closing the scope. if (Cond.isUsable()) - Cond = Actions.CorrectDelayedTyposInExpr(Cond); + Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); else { if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) SkipUntil(tok::semi); @@ -2157,11 +2189,13 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // for-range-declaration next. bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl(); ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); + SourceLocation SecondPartStart = Tok.getLocation(); + Sema::ConditionKind CK = Sema::ConditionKind::Boolean; SecondPart = ParseCXXCondition( - nullptr, ForLoc, Sema::ConditionKind::Boolean, + /*InitStmt=*/nullptr, ForLoc, CK, // FIXME: recovery if we don't see another semi! /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr, - /*EnterForConditionScope*/ true); + /*EnterForConditionScope=*/true); if (ForRangeInfo.ParsedForRangeDecl()) { Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc() @@ -2177,6 +2211,19 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { << FixItHint::CreateRemoval(EmptyInitStmtSemiLoc); } } + + if (SecondPart.isInvalid()) { + ExprResult CondExpr = Actions.CreateRecoveryExpr( + SecondPartStart, + Tok.getLocation() == SecondPartStart ? SecondPartStart + : PrevTokLocation, + {}, Actions.PreferredConditionType(CK)); + if (!CondExpr.isInvalid()) + SecondPart = Actions.ActOnCondition(getCurScope(), ForLoc, + CondExpr.get(), CK, + /*MissingOK=*/false); + } + } else { // We permit 'continue' and 'break' in the condition of a for loop. getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp index fc661d21b63a..64fe4d50bba2 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp @@ -248,12 +248,16 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( : MultiTemplateParamsArg(), TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation, AnonRecord); + Actions.ActOnDefinedDeclarationSpecifier(Decl); assert(!AnonRecord && "Anonymous unions/structs should not be valid with template"); DS.complete(Decl); return Decl; } + if (DS.hasTagDefinition()) + Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl()); + // Move the attributes from the prefix into the DS. if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) ProhibitAttributes(prefixAttrs); @@ -1058,8 +1062,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { ++CurTemplateDepthTracker; EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - DefaultArg = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseInitializer()); if (DefaultArg.isInvalid()) SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); } @@ -1578,6 +1581,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { /// constant-expression /// type-id /// id-expression +/// braced-init-list [C++26, DR] +/// ParsedTemplateArgument Parser::ParseTemplateArgument() { // C++ [temp.arg]p2: // In a template-argument, an ambiguity between a type-id and an @@ -1615,8 +1620,12 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { } // Parse a non-type template argument. + ExprResult ExprArg; SourceLocation Loc = Tok.getLocation(); - ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast); + if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) + ExprArg = ParseBraceInitializer(); + else + ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast); if (ExprArg.isInvalid() || !ExprArg.get()) { return ParsedTemplateArgument(); } diff --git a/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp index 664337052500..242741c15b5f 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp @@ -83,6 +83,17 @@ bool Parser::isCXXDeclarationStatement( isDeductionGuide, DeclSpec::FriendSpecified::No)) return true; + } else if (SS.isNotEmpty()) { + // If the scope is not empty, it could alternatively be something like + // a typedef or using declaration. That declaration might be private + // in the global context, which would be diagnosed by calling into + // isCXXSimpleDeclaration, but may actually be fine in the context of + // member functions and static variable definitions. Check if the next + // token is also an identifier and assume a declaration. + // We cannot check if the scopes match because the declarations could + // involve namespaces and friend declarations. + if (NextToken().is(tok::identifier)) + return true; } break; } @@ -1518,6 +1529,9 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, // HLSL address space qualifiers case tok::kw_groupshared: + case tok::kw_in: + case tok::kw_inout: + case tok::kw_out: // GNU case tok::kw_restrict: @@ -1560,6 +1574,17 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, case tok::kw___vector: return TPResult::True; + case tok::kw_this: { + // Try to parse a C++23 Explicit Object Parameter + // We do that in all language modes to produce a better diagnostic. + if (getLangOpts().CPlusPlus) { + RevertingTentativeParsingAction PA(*this); + ConsumeToken(); + return isCXXDeclarationSpecifier(AllowImplicitTypename, BracedCastResult, + InvalidAsDeclSpec); + } + return TPResult::False; + } case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); // If lookup for the template-name found nothing, don't assume we have a @@ -1753,6 +1778,9 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, case tok::kw___ibm128: case tok::kw_void: case tok::annot_decltype: + case tok::kw__Accum: + case tok::kw__Fract: + case tok::kw__Sat: #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" if (NextToken().is(tok::l_paren)) @@ -1872,6 +1900,9 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw_void: case tok::kw___unknown_anytype: case tok::kw___auto_type: + case tok::kw__Accum: + case tok::kw__Fract: + case tok::kw__Sat: #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" return true; diff --git a/contrib/llvm-project/clang/lib/Parse/Parser.cpp b/contrib/llvm-project/clang/lib/Parse/Parser.cpp index b1ccbeb99e58..b703c2d9b8e0 100644 --- a/contrib/llvm-project/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm-project/clang/lib/Parse/Parser.cpp @@ -13,8 +13,8 @@ #include "clang/Parse/Parser.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTLambda.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Basic/FileManager.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -22,6 +22,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -317,6 +318,13 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { return false; ConsumeAnnotationToken(); break; + case tok::annot_pragma_openacc: + case tok::annot_pragma_openacc_end: + // Stop before an OpenACC pragma boundary. + if (OpenACCDirectiveParsing) + return false; + ConsumeAnnotationToken(); + break; case tok::annot_module_begin: case tok::annot_module_end: case tok::annot_module_include: @@ -615,6 +623,11 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, Sema::ModuleImportState &ImportState) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this); + // Skip over the EOF token, flagging end of previous input for incremental + // processing + if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) + ConsumeToken(); + Result = nullptr; switch (Tok.getKind()) { case tok::annot_pragma_unused: @@ -831,6 +844,9 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); return nullptr; + case tok::annot_pragma_cx_limited_range: + HandlePragmaCXLimitedRange(); + return nullptr; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); return nullptr; @@ -845,6 +861,8 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, AccessSpecifier AS = AS_none; return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs); } + case tok::annot_pragma_openacc: + return ParseOpenACCDirectiveDecl(); case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); return nullptr; @@ -923,9 +941,16 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, /*IsInstanceMethod=*/std::nullopt, /*ReturnType=*/nullptr); } - Actions.CodeCompleteOrdinaryName( - getCurScope(), - CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); + + Sema::ParserCompletionContext PCC; + if (CurParsedObjCImpl) { + PCC = Sema::PCC_ObjCImplementation; + } else if (PP.isIncrementalProcessingEnabled()) { + PCC = Sema::PCC_TopLevelOrExpression; + } else { + PCC = Sema::PCC_Namespace; + }; + Actions.CodeCompleteOrdinaryName(getCurScope(), PCC); return nullptr; case tok::kw_import: { Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module; @@ -1031,7 +1056,7 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, ConsumeToken(); return nullptr; } - if (PP.isIncrementalProcessingEnabled() && + if (getLangOpts().IncrementalExtensions && !isDeclarationStatement(/*DisambiguatingWithExpression=*/true)) return ParseTopLevelStmtDecl(); @@ -1157,6 +1182,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord); DS.complete(TheDecl); + Actions.ActOnDefinedDeclarationSpecifier(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; return Actions.BuildDeclaratorGroup(decls); @@ -1164,6 +1190,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( return Actions.ConvertDeclToDeclGroup(TheDecl); } + if (DS.hasTagDefinition()) + Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl()); + // ObjC2 allows prefix attributes on class interfaces and protocols. // FIXME: This still needs better diagnostics. We should only accept // attributes here, no types, etc. @@ -1213,6 +1242,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec *DS, AccessSpecifier AS) { + // Add an enclosing time trace scope for a bunch of small scopes with + // "EvaluateAsConstExpr". + llvm::TimeTraceScope TimeScope("ParseDeclarationOrFunctionDefinition", [&]() { + return Tok.getLocation().printToString( + Actions.getASTContext().getSourceManager()); + }); + if (DS) { return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, *DS, AS); } else { @@ -1243,6 +1279,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, LateParsedAttrList *LateParsedAttrs) { + llvm::TimeTraceScope TimeScope("ParseFunctionDefinition", [&]() { + return Actions.GetNameForDeclarator(D).getName().getAsString(); + }); + // Poison SEH identifiers so they are flagged as illegal in function bodies. PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); @@ -1433,12 +1473,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // With abbreviated function templates - we need to explicitly add depth to // account for the implicit template parameter list induced by the template. - if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res)) - if (Template->isAbbreviated() && - Template->getTemplateParameters()->getParam(0)->isImplicit()) - // First template parameter is implicit - meaning no explicit template - // parameter list was specified. - CurTemplateDepthTracker.addDepth(1); + if (const auto *Template = dyn_cast_if_present<FunctionTemplateDecl>(Res); + Template && Template->isAbbreviated() && + Template->getTemplateParameters()->getParam(0)->isImplicit()) + // First template parameter is implicit - meaning no explicit template + // parameter list was specified. + CurTemplateDepthTracker.addDepth(1); if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) && trySkippingFunctionBody()) { @@ -2107,7 +2147,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec( } if (!getLangOpts().CPlusPlus) { - // If we're in C, the only place we can have :: tokens is C2x + // If we're in C, the only place we can have :: tokens is C23 // attribute which is parsed elsewhere. If the identifier is not a type, // then it can't be scope either, just early exit. return false; @@ -2548,6 +2588,10 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, SeenError = false; break; case Sema::ModuleImportState::FirstDecl: + // If we found an import decl as the first declaration, we must be not in + // a C++20 module unit or we are in an invalid state. + ImportState = Sema::ModuleImportState::NotACXX20Module; + [[fallthrough]]; case Sema::ModuleImportState::NotACXX20Module: // We can only import a partition within a module purview. if (IsPartition) @@ -2601,7 +2645,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, auto &SrcMgr = PP.getSourceManager(); auto FE = SrcMgr.getFileEntryRefForID(SrcMgr.getFileID(AtLoc)); if (FE && llvm::sys::path::parent_path(FE->getDir().getName()) - .endswith(".framework")) + .ends_with(".framework")) Diags.Report(AtLoc, diag::warn_atimport_in_framework_header); } |