aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Parse
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-12-18 20:30:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-04-06 20:11:55 +0000
commit5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch)
tree1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/clang/lib/Parse
parent3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff)
parent312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff)
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse')
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp5
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp307
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp79
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp116
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseExprCXX.cpp227
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseInit.cpp8
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseObjc.cpp64
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp527
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp205
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParsePragma.cpp183
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp83
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseTemplate.cpp15
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseTentative.cpp31
-rw-r--r--contrib/llvm-project/clang/lib/Parse/Parser.cpp70
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);
}