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