aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse')
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp1
-rw-r--r--clang/lib/Parse/ParseDecl.cpp180
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp428
-rw-r--r--clang/lib/Parse/ParseExpr.cpp51
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp328
-rw-r--r--clang/lib/Parse/ParseInit.cpp28
-rw-r--r--clang/lib/Parse/ParseObjc.cpp94
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp425
-rw-r--r--clang/lib/Parse/ParsePragma.cpp30
-rw-r--r--clang/lib/Parse/ParseStmt.cpp80
-rw-r--r--clang/lib/Parse/ParseStmtAsm.cpp17
-rw-r--r--clang/lib/Parse/ParseTentative.cpp2
-rw-r--r--clang/lib/Parse/Parser.cpp37
13 files changed, 1133 insertions, 568 deletions
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index b0335905b6f8..116724a0d50b 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -778,6 +778,7 @@ void Parser::ParseLexedPragma(LateParsedPragma &LP) {
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert(Tok.isAnnotation() && "Expected annotation token.");
switch (Tok.getKind()) {
+ case tok::annot_attr_openmp:
case tok::annot_pragma_openmp: {
AccessSpecifier AS = LP.getAccessSpecifier();
ParsedAttributesWithRange Attrs(AttrFactory);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 571164139630..f4f5f461e3b6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -103,6 +103,24 @@ static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
return AttrStartIsInMacro && AttrEndIsInMacro;
}
+void Parser::ParseAttributes(unsigned WhichAttrKinds,
+ ParsedAttributesWithRange &Attrs,
+ SourceLocation *End,
+ LateParsedAttrList *LateAttrs) {
+ bool MoreToParse;
+ do {
+ // Assume there's nothing left to parse, but if any attributes are in fact
+ // parsed, loop to ensure all specified attribute combinations are parsed.
+ MoreToParse = false;
+ if (WhichAttrKinds & PAKM_CXX11)
+ MoreToParse |= MaybeParseCXX11Attributes(Attrs, End);
+ if (WhichAttrKinds & PAKM_GNU)
+ MoreToParse |= MaybeParseGNUAttributes(Attrs, End, LateAttrs);
+ if (WhichAttrKinds & PAKM_Declspec)
+ MoreToParse |= MaybeParseMicrosoftDeclSpecs(Attrs, End);
+ } while (MoreToParse);
+}
+
/// ParseGNUAttributes - Parse a non-empty attributes list.
///
/// [GNU] attributes:
@@ -144,15 +162,19 @@ static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
/// ',' or ')' are ignored, otherwise they produce a parse error.
///
/// We follow the C++ model, but don't allow junk after the identifier.
-void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
- SourceLocation *endLoc,
- LateParsedAttrList *LateAttrs,
- Declarator *D) {
+void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs,
+ SourceLocation *EndLoc,
+ LateParsedAttrList *LateAttrs, Declarator *D) {
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
+ SourceLocation StartLoc = Tok.getLocation(), Loc;
+
+ if (!EndLoc)
+ EndLoc = &Loc;
+
while (Tok.is(tok::kw___attribute)) {
SourceLocation AttrTokLoc = ConsumeToken();
- unsigned OldNumAttrs = attrs.size();
+ unsigned OldNumAttrs = Attrs.size();
unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0;
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
@@ -180,14 +202,14 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation AttrNameLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren)) {
- attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
ParsedAttr::AS_GNU);
continue;
}
// Handle "parameterized" attributes
if (!LateAttrs || !isAttributeLateParsed(*AttrName)) {
- ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr,
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, nullptr,
SourceLocation(), ParsedAttr::AS_GNU, D);
continue;
}
@@ -220,8 +242,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation Loc = Tok.getLocation();
if (ExpectAndConsume(tok::r_paren))
SkipUntil(tok::r_paren, StopAtSemi);
- if (endLoc)
- *endLoc = Loc;
+ if (EndLoc)
+ *EndLoc = Loc;
// If this was declared in a macro, attach the macro IdentifierInfo to the
// parsed attribute.
@@ -233,8 +255,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
Lexer::getSourceText(ExpansionRange, SM, PP.getLangOpts());
IdentifierInfo *MacroII = PP.getIdentifierInfo(FoundName);
- for (unsigned i = OldNumAttrs; i < attrs.size(); ++i)
- attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());
+ for (unsigned i = OldNumAttrs; i < Attrs.size(); ++i)
+ Attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());
if (LateAttrs) {
for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i)
@@ -242,6 +264,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
}
}
+
+ Attrs.Range = SourceRange(StartLoc, *EndLoc);
}
/// Determine whether the given attribute has an identifier argument.
@@ -1589,7 +1613,30 @@ void Parser::DiagnoseProhibitedAttributes(
}
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
- unsigned DiagID) {
+ unsigned DiagID, bool DiagnoseEmptyAttrs) {
+
+ if (DiagnoseEmptyAttrs && Attrs.empty() && Attrs.Range.isValid()) {
+ // An attribute list has been parsed, but it was empty.
+ // This is the case for [[]].
+ const auto &LangOpts = getLangOpts();
+ auto &SM = PP.getSourceManager();
+ Token FirstLSquare;
+ Lexer::getRawToken(Attrs.Range.getBegin(), FirstLSquare, SM, LangOpts);
+
+ if (FirstLSquare.is(tok::l_square)) {
+ llvm::Optional<Token> SecondLSquare =
+ Lexer::findNextToken(FirstLSquare.getLocation(), SM, LangOpts);
+
+ if (SecondLSquare && SecondLSquare->is(tok::l_square)) {
+ // The attribute range starts with [[, but is empty. So this must
+ // be [[]], which we are supposed to diagnose because
+ // DiagnoseEmptyAttrs is true.
+ Diag(Attrs.Range.getBegin(), DiagID) << Attrs.Range;
+ return;
+ }
+ }
+ }
+
for (const ParsedAttr &AL : Attrs) {
if (!AL.isCXX11Attribute() && !AL.isC2xAttribute())
continue;
@@ -1603,6 +1650,13 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
}
}
+void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributesWithRange &Attrs) {
+ for (const ParsedAttr &PA : Attrs) {
+ if (PA.isCXX11Attribute() || PA.isC2xAttribute())
+ Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.getRange();
+ }
+}
+
// Usually, `__attribute__((attrib)) class Foo {} var` means that attribute
// applies to var, not the type Foo.
// As an exception to the rule, __declspec(align(...)) before the
@@ -1952,8 +2006,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Check to see if we have a function *definition* which must have a body.
if (D.isFunctionDeclarator()) {
if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) {
- Actions.CodeCompleteAfterFunctionEquals(D);
cutOffParsing();
+ Actions.CodeCompleteAfterFunctionEquals(D);
return nullptr;
}
// Look at the next token to make sure that this isn't a function
@@ -2292,9 +2346,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
InitializerScopeRAII InitScope(*this, D, ThisDecl);
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteInitializer(getCurScope(), ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
- cutOffParsing();
return nullptr;
}
@@ -3024,6 +3078,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
SourceLocation Loc = Tok.getLocation();
+ // Helper for image types in OpenCL.
+ auto handleOpenCLImageKW = [&] (StringRef Ext, TypeSpecifierType ImageTypeSpec) {
+ // Check if the image type is supported and otherwise turn the keyword into an identifier
+ // because image types from extensions are not reserved identifiers.
+ if (!StringRef(Ext).empty() && !getActions().getOpenCLOptions().isSupported(Ext, getLangOpts())) {
+ Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
+ Tok.setKind(tok::identifier);
+ return false;
+ }
+ isInvalid = DS.SetTypeSpecType(ImageTypeSpec, Loc, PrevSpec, DiagID, Policy);
+ return true;
+ };
+
switch (Tok.getKind()) {
default:
DoneWithDeclSpec:
@@ -3072,10 +3139,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
= DSContext == DeclSpecContext::DSC_top_level ||
(DSContext == DeclSpecContext::DSC_class && DS.isFriendSpecified());
+ cutOffParsing();
Actions.CodeCompleteDeclSpec(getCurScope(), DS,
AllowNonIdentifiers,
AllowNestedNameSpecifiers);
- return cutOffParsing();
+ return;
}
if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
@@ -3088,8 +3156,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
else if (CurParsedObjCImpl)
CCC = Sema::PCC_ObjCImplementation;
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
- return cutOffParsing();
+ return;
}
case tok::coloncolon: // ::foo::bar
@@ -3485,14 +3554,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
- // GNU attributes support.
+ // Attributes support.
case tok::kw___attribute:
- ParseGNUAttributes(DS.getAttributes(), nullptr, LateAttrs);
- continue;
-
- // Microsoft declspec support.
case tok::kw___declspec:
- ParseMicrosoftDeclSpecs(DS.getAttributes());
+ ParseAttributes(PAKM_GNU | PAKM_Declspec, DS.getAttributes(), nullptr,
+ LateAttrs);
continue;
// Microsoft single token adornments.
@@ -3631,8 +3697,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// C++ for OpenCL does not allow virtual function qualifier, to avoid
// function pointers restricted in OpenCL v2.0 s6.9.a.
if (getLangOpts().OpenCLCPlusPlus &&
- !getActions().getOpenCLOptions().isEnabled(
- "__cl_clang_function_pointers")) {
+ !getActions().getOpenCLOptions().isAvailableOption(
+ "__cl_clang_function_pointers", getLangOpts())) {
DiagID = diag::err_openclcxx_virtual_function;
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
isInvalid = true;
@@ -3881,18 +3947,22 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_pipe:
if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200 &&
!getLangOpts().OpenCLCPlusPlus)) {
- // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should
- // support the "pipe" word as identifier.
+ // OpenCL 2.0 and later define this keyword. OpenCL 1.2 and earlier
+ // should support the "pipe" word as identifier.
Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
+ Tok.setKind(tok::identifier);
goto DoneWithDeclSpec;
}
isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
break;
-#define GENERIC_IMAGE_TYPE(ImgType, Id) \
- case tok::kw_##ImgType##_t: \
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, \
- DiagID, Policy); \
- break;
+// We only need to enumerate each image type once.
+#define IMAGE_READ_WRITE_TYPE(Type, Id, Ext)
+#define IMAGE_WRITE_TYPE(Type, Id, Ext)
+#define IMAGE_READ_TYPE(ImgType, Id, Ext) \
+ case tok::kw_##ImgType##_t: \
+ if (!handleOpenCLImageKW(Ext, DeclSpec::TST_##ImgType##_t)) \
+ goto DoneWithDeclSpec; \
+ break;
#include "clang/Basic/OpenCLImageTypes.def"
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
@@ -4002,8 +4072,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___generic:
// generic address space is introduced only in OpenCL v2.0
// see OpenCL C Spec v2.0 s6.5.5
- if (Actions.getLangOpts().OpenCLVersion < 200 &&
- !Actions.getLangOpts().OpenCLCPlusPlus) {
+ // OpenCL v3.0 introduces __opencl_c_generic_address_space
+ // feature macro to indicate if generic address space is supported
+ if (!Actions.getLangOpts().OpenCLGenericAddressSpace) {
DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
isInvalid = true;
@@ -4216,7 +4287,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
// Parse _Static_assert declaration.
- if (Tok.is(tok::kw__Static_assert)) {
+ if (Tok.isOneOf(tok::kw__Static_assert, tok::kw_static_assert)) {
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
continue;
@@ -4232,7 +4303,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
- if (Tok.is(tok::annot_pragma_openmp)) {
+ if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) {
// Result can be ignored, because it must be always empty.
AccessSpecifier AS = AS_none;
ParsedAttributesWithRange Attrs(AttrFactory);
@@ -4348,15 +4419,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Parse the tag portion of this.
if (Tok.is(tok::code_completion)) {
// Code completion for an enum name.
+ cutOffParsing();
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
- return cutOffParsing();
+ return;
}
// If attributes exist after tag, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseGNUAttributes(attrs);
- MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftDeclSpecs(attrs);
+ MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs);
SourceLocation ScopedEnumKWLoc;
bool IsScopedUsingClassTag = false;
@@ -4373,9 +4443,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
ProhibitAttributes(attrs);
// They are allowed afterwards, though.
- MaybeParseGNUAttributes(attrs);
- MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftDeclSpecs(attrs);
+ MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs);
}
// C++11 [temp.explicit]p12:
@@ -4617,7 +4685,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// or opaque-enum-declaration anywhere.
if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt &&
!getLangOpts().ObjC) {
- ProhibitAttributes(attrs);
+ ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+ /*DiagnoseEmptyAttrs=*/true);
if (BaseType.isUsable())
Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier)
<< (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes) << BaseRange;
@@ -4761,7 +4830,6 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// If attributes exist after the enumerator, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- ProhibitAttributes(attrs); // GNU-style attributes are prohibited.
if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
if (getLangOpts().CPlusPlus)
Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
@@ -5059,8 +5127,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
default: return false;
case tok::kw_pipe:
- return (getLangOpts().OpenCL && getLangOpts().OpenCLVersion >= 200) ||
- getLangOpts().OpenCLCPlusPlus;
+ return getLangOpts().OpenCLPipe;
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
@@ -5180,6 +5247,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_friend:
// static_assert-declaration
+ case tok::kw_static_assert:
case tok::kw__Static_assert:
// GNU typeof support.
@@ -5448,11 +5516,12 @@ void Parser::ParseTypeQualifierListOpt(
switch (Tok.getKind()) {
case tok::code_completion:
+ cutOffParsing();
if (CodeCompletionHandler)
(*CodeCompletionHandler)();
else
Actions.CodeCompleteTypeQualifiers(DS);
- return cutOffParsing();
+ return;
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
@@ -5587,8 +5656,7 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
if (Kind == tok::star || Kind == tok::caret)
return true;
- if (Kind == tok::kw_pipe &&
- ((Lang.OpenCL && Lang.OpenCLVersion >= 200) || Lang.OpenCLCPlusPlus))
+ if (Kind == tok::kw_pipe && Lang.OpenCLPipe)
return true;
if (!Lang.CPlusPlus)
@@ -6990,8 +7058,9 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
std::move(attrs), T.getCloseLocation());
return;
} else if (Tok.getKind() == tok::code_completion) {
+ cutOffParsing();
Actions.CodeCompleteBracketDeclarator(getCurScope());
- return cutOffParsing();
+ return;
}
// If valid, this location is the position where we read the 'static' keyword.
@@ -7274,6 +7343,7 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() {
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
+ case tok::kw__Bool:
case tok::kw___bool:
case tok::kw___pixel:
Tok.setKind(tok::kw___vector);
@@ -7283,7 +7353,8 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() {
Tok.setKind(tok::kw___vector);
return true;
}
- if (Next.getIdentifierInfo() == Ident_bool) {
+ if (Next.getIdentifierInfo() == Ident_bool ||
+ Next.getIdentifierInfo() == Ident_Bool) {
Tok.setKind(tok::kw___vector);
return true;
}
@@ -7308,6 +7379,7 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
+ case tok::kw__Bool:
case tok::kw___bool:
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
@@ -7317,8 +7389,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy);
return true;
}
- if (Next.getIdentifierInfo() == Ident_bool) {
- isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy);
+ if (Next.getIdentifierInfo() == Ident_bool ||
+ Next.getIdentifierInfo() == Ident_Bool) {
+ isInvalid =
+ DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
return true;
}
break;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 88ebb59f9a60..ca5c013a51fe 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -63,8 +63,8 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteNamespaceDecl(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteNamespaceDecl(getCurScope());
return nullptr;
}
@@ -132,7 +132,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
<< FixItHint::CreateRemoval(InlineLoc);
Decl *NSAlias = ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
return Actions.ConvertDeclToDeclGroup(NSAlias);
-}
+ }
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
@@ -283,8 +283,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
ConsumeToken(); // eat the '='.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
return nullptr;
}
@@ -471,8 +471,8 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context,
SourceLocation UsingLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteUsing(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteUsing(getCurScope());
return nullptr;
}
@@ -497,11 +497,7 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context,
}
// Otherwise, it must be a using-declaration or an alias-declaration.
-
- // Using declarations can't have attributes.
- ProhibitAttributes(attrs);
-
- return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
+ return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, attrs,
AS_none);
}
@@ -525,8 +521,8 @@ Decl *Parser::ParseUsingDirective(DeclaratorContext Context,
SourceLocation NamespcLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteUsingDirective(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteUsingDirective(getCurScope());
return nullptr;
}
@@ -627,7 +623,8 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
if (getLangOpts().CPlusPlus11 && Context == DeclaratorContext::Member &&
Tok.is(tok::identifier) &&
(NextToken().is(tok::semi) || NextToken().is(tok::comma) ||
- NextToken().is(tok::ellipsis)) &&
+ NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) ||
+ NextToken().is(tok::kw___attribute)) &&
D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
!D.SS.getScopeRep()->getAsNamespace() &&
!D.SS.getScopeRep()->getAsNamespaceAlias()) {
@@ -670,11 +667,48 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
/// alias-declaration: C++11 [dcl.dcl]p1
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
///
+/// using-enum-declaration: [C++20, dcl.enum]
+/// 'using' elaborated-enum-specifier ;
+///
+/// elaborated-enum-specifier:
+/// 'enum' nested-name-specifier[opt] identifier
Parser::DeclGroupPtrTy
-Parser::ParseUsingDeclaration(DeclaratorContext Context,
- const ParsedTemplateInfo &TemplateInfo,
- SourceLocation UsingLoc, SourceLocation &DeclEnd,
- AccessSpecifier AS) {
+Parser::ParseUsingDeclaration(
+ DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
+ SourceLocation UsingLoc, SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &PrefixAttrs, AccessSpecifier AS) {
+ SourceLocation UELoc;
+ if (TryConsumeToken(tok::kw_enum, UELoc)) {
+ // C++20 using-enum
+ Diag(UELoc, getLangOpts().CPlusPlus20
+ ? diag::warn_cxx17_compat_using_enum_declaration
+ : diag::ext_using_enum_declaration);
+
+ DiagnoseCXX11AttributeExtension(PrefixAttrs);
+
+ DeclSpec DS(AttrFactory);
+ ParseEnumSpecifier(UELoc, DS, TemplateInfo, AS,
+ // DSC_trailing has the semantics we desire
+ DeclSpecContext::DSC_trailing);
+
+ if (TemplateInfo.Kind) {
+ SourceRange R = TemplateInfo.getSourceRange();
+ Diag(UsingLoc, diag::err_templated_using_directive_declaration)
+ << 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
+
+ return nullptr;
+ }
+
+ Decl *UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
+ UELoc, DS);
+ DeclEnd = Tok.getLocation();
+ if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ "using-enum declaration"))
+ SkipUntil(tok::semi);
+
+ return Actions.ConvertDeclToDeclGroup(UED);
+ }
+
// Check for misplaced attributes before the identifier in an
// alias-declaration.
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
@@ -684,8 +718,18 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
bool InvalidDeclarator = ParseUsingDeclarator(Context, D);
ParsedAttributesWithRange Attrs(AttrFactory);
- MaybeParseGNUAttributes(Attrs);
- MaybeParseCXX11Attributes(Attrs);
+ MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);
+
+ // If we had any misplaced attributes from earlier, this is where they
+ // should have been written.
+ if (MisplacedAttrs.Range.isValid()) {
+ Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
+ << FixItHint::CreateInsertionFromRange(
+ Tok.getLocation(),
+ CharSourceRange::getTokenRange(MisplacedAttrs.Range))
+ << FixItHint::CreateRemoval(MisplacedAttrs.Range);
+ Attrs.takeAllFrom(MisplacedAttrs);
+ }
// Maybe this is an alias-declaration.
if (Tok.is(tok::equal)) {
@@ -694,16 +738,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
return nullptr;
}
- // If we had any misplaced attributes from earlier, this is where they
- // should have been written.
- if (MisplacedAttrs.Range.isValid()) {
- Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
- << FixItHint::CreateInsertionFromRange(
- Tok.getLocation(),
- CharSourceRange::getTokenRange(MisplacedAttrs.Range))
- << FixItHint::CreateRemoval(MisplacedAttrs.Range);
- Attrs.takeAllFrom(MisplacedAttrs);
- }
+ ProhibitAttributes(PrefixAttrs);
Decl *DeclFromDeclSpec = nullptr;
Decl *AD = ParseAliasDeclarationAfterDeclarator(
@@ -711,10 +746,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec);
}
- // C++11 attributes are not allowed on a using-declaration, but GNU ones
- // are.
- ProhibitAttributes(MisplacedAttrs);
- ProhibitAttributes(Attrs);
+ DiagnoseCXX11AttributeExtension(PrefixAttrs);
// Diagnose an attempt to declare a templated using-declaration.
// In C++11, alias-declarations can be templates:
@@ -732,8 +764,10 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
SmallVector<Decl *, 8> DeclsInGroup;
while (true) {
- // Parse (optional) attributes (most likely GNU strong-using extension).
- MaybeParseGNUAttributes(Attrs);
+ // Parse (optional) attributes.
+ MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);
+ DiagnoseCXX11AttributeExtension(Attrs);
+ Attrs.addAll(PrefixAttrs.begin(), PrefixAttrs.end());
if (InvalidDeclarator)
SkipUntil(tok::comma, tok::semi, StopBeforeMatch);
@@ -772,8 +806,9 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
// Eat ';'.
DeclEnd = Tok.getLocation();
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
- !Attrs.empty() ? "attributes list"
- : "using declaration"))
+ !Attrs.empty() ? "attributes list"
+ : UELoc.isValid() ? "using-enum declaration"
+ : "using declaration"))
SkipUntil(tok::semi);
return Actions.BuildDeclaratorGroup(DeclsInGroup);
@@ -857,6 +892,16 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
DeclFromDeclSpec);
}
+static FixItHint getStaticAssertNoMessageFixIt(const Expr *AssertExpr,
+ SourceLocation EndExprLoc) {
+ if (const auto *BO = dyn_cast_or_null<BinaryOperator>(AssertExpr)) {
+ if (BO->getOpcode() == BO_LAnd &&
+ isa<StringLiteral>(BO->getRHS()->IgnoreImpCasts()))
+ return FixItHint::CreateReplacement(BO->getOperatorLoc(), ",");
+ }
+ return FixItHint::CreateInsertion(EndExprLoc, ", \"\"");
+}
+
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
///
/// [C++0x] static_assert-declaration:
@@ -871,8 +916,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
Diag(Tok, diag::ext_c11_feature) << Tok.getName();
- if (Tok.is(tok::kw_static_assert))
- Diag(Tok, diag::warn_cxx98_compat_static_assert);
+ if (Tok.is(tok::kw_static_assert)) {
+ if (!getLangOpts().CPlusPlus)
+ Diag(Tok, diag::ext_ms_static_assert)
+ << FixItHint::CreateReplacement(Tok.getLocation(), "_Static_assert");
+ else
+ Diag(Tok, diag::warn_cxx98_compat_static_assert);
+ }
SourceLocation StaticAssertLoc = ConsumeToken();
@@ -893,12 +943,17 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
ExprResult AssertMessage;
if (Tok.is(tok::r_paren)) {
- Diag(Tok, getLangOpts().CPlusPlus17
- ? diag::warn_cxx14_compat_static_assert_no_message
- : diag::ext_static_assert_no_message)
- << (getLangOpts().CPlusPlus17
- ? FixItHint()
- : FixItHint::CreateInsertion(Tok.getLocation(), ", \"\""));
+ unsigned DiagVal;
+ if (getLangOpts().CPlusPlus17)
+ DiagVal = diag::warn_cxx14_compat_static_assert_no_message;
+ else if (getLangOpts().CPlusPlus)
+ DiagVal = diag::ext_cxx_static_assert_no_message;
+ else if (getLangOpts().C2x)
+ DiagVal = diag::warn_c17_compat_static_assert_no_message;
+ else
+ DiagVal = diag::ext_c_static_assert_no_message;
+ Diag(Tok, DiagVal) << getStaticAssertNoMessageFixIt(AssertExpr.get(),
+ Tok.getLocation());
} else {
if (ExpectAndConsume(tok::comma)) {
SkipUntil(tok::semi);
@@ -1414,8 +1469,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::code_completion)) {
// Code completion for a struct, class, or union name.
+ cutOffParsing();
Actions.CodeCompleteTag(getCurScope(), TagType);
- return cutOffParsing();
+ return;
}
// C++03 [temp.explicit] 14.7.2/8:
@@ -1435,8 +1491,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ParsedAttributesWithRange attrs(AttrFactory);
// If attributes exist after tag, parse them.
- MaybeParseGNUAttributes(attrs);
- MaybeParseMicrosoftDeclSpecs(attrs);
+ MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
// Parse inheritance specifiers.
if (Tok.isOneOf(tok::kw___single_inheritance,
@@ -1444,10 +1499,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
tok::kw___virtual_inheritance))
ParseMicrosoftInheritanceClassAttributes(attrs);
- // If C++0x attributes exist here, parse them.
- // FIXME: Are we consistent with the ordering of parsing of different
- // styles of attributes?
- MaybeParseCXX11Attributes(attrs);
+ // Allow attributes to precede or succeed the inheritance specifiers.
+ MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
// Source location used by FIXIT to insert misplaced
// C++11 attributes
@@ -1693,7 +1746,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TUK = Sema::TUK_Reference;
else if (Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- (isCXX11FinalKeyword() &&
+ (isClassCompatibleKeyword() &&
(NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) {
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
@@ -1709,14 +1762,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Okay, this is a class definition.
TUK = Sema::TUK_Definition;
}
- } else if (isCXX11FinalKeyword() && (NextToken().is(tok::l_square) ||
- NextToken().is(tok::kw_alignas))) {
+ } else if (isClassCompatibleKeyword() &&
+ (NextToken().is(tok::l_square) ||
+ NextToken().is(tok::kw_alignas) ||
+ isCXX11VirtSpecifier(NextToken()) != VirtSpecifiers::VS_None)) {
// We can't tell if this is a definition or reference
// until we skipped the 'final' and C++11 attribute specifiers.
TentativeParsingAction PA(*this);
- // Skip the 'final' keyword.
- ConsumeToken();
+ // Skip the 'final', abstract'... keywords.
+ while (isClassCompatibleKeyword()) {
+ ConsumeToken();
+ }
// Skip C++11 attribute specifiers.
while (true) {
@@ -1819,7 +1876,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
// This is an explicit instantiation of a class template.
- ProhibitAttributes(attrs);
+ ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+ /*DiagnoseEmptyAttrs=*/true);
TagOrTempResult = Actions.ActOnExplicitInstantiation(
getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc,
@@ -1834,7 +1892,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (TUK == Sema::TUK_Reference ||
(TUK == Sema::TUK_Friend &&
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
- ProhibitAttributes(attrs);
+ ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+ /*DiagnoseEmptyAttrs=*/true);
TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
SS,
TemplateId->TemplateKWLoc,
@@ -1906,7 +1965,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TagType, StartLoc, SS, Name, NameLoc, attrs);
} else if (TUK == Sema::TUK_Friend &&
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
- ProhibitAttributes(attrs);
+ ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+ /*DiagnoseEmptyAttrs=*/true);
TagOrTempResult = Actions.ActOnTemplatedFriendTag(
getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name,
@@ -1915,7 +1975,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams ? TemplateParams->size() : 0));
} else {
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
- ProhibitAttributes(attrs);
+ ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+ /* DiagnoseEmptyAttrs=*/true);
if (TUK == Sema::TUK_Definition &&
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
@@ -1961,7 +2022,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX11FinalKeyword());
+ isClassCompatibleKeyword());
if (SkipBody.ShouldSkip)
SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
TagOrTempResult.get());
@@ -2228,8 +2289,10 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
Ident_final = &PP.getIdentifierTable().get("final");
if (getLangOpts().GNUKeywords)
Ident_GNU_final = &PP.getIdentifierTable().get("__final");
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt) {
Ident_sealed = &PP.getIdentifierTable().get("sealed");
+ Ident_abstract = &PP.getIdentifierTable().get("abstract");
+ }
Ident_override = &PP.getIdentifierTable().get("override");
}
@@ -2239,6 +2302,9 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
if (II == Ident_sealed)
return VirtSpecifiers::VS_Sealed;
+ if (II == Ident_abstract)
+ return VirtSpecifiers::VS_Abstract;
+
if (II == Ident_final)
return VirtSpecifiers::VS_Final;
@@ -2284,6 +2350,8 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
<< VirtSpecifiers::getSpecifierName(Specifier);
} else if (Specifier == VirtSpecifiers::VS_Sealed) {
Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword);
+ } else if (Specifier == VirtSpecifiers::VS_Abstract) {
+ Diag(Tok.getLocation(), diag::ext_ms_abstract_keyword);
} else if (Specifier == VirtSpecifiers::VS_GNU_Final) {
Diag(Tok.getLocation(), diag::ext_warn_gnu_final);
} else {
@@ -2306,6 +2374,16 @@ bool Parser::isCXX11FinalKeyword() const {
Specifier == VirtSpecifiers::VS_Sealed;
}
+/// isClassCompatibleKeyword - Determine whether the next token is a C++11
+/// 'final' or Microsoft 'sealed' or 'abstract' contextual keywords.
+bool Parser::isClassCompatibleKeyword() const {
+ VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
+ return Specifier == VirtSpecifiers::VS_Final ||
+ Specifier == VirtSpecifiers::VS_GNU_Final ||
+ Specifier == VirtSpecifiers::VS_Sealed ||
+ Specifier == VirtSpecifiers::VS_Abstract;
+}
+
/// Parse a C++ member-declarator up to, but not including, the optional
/// brace-or-equal-initializer or pure-specifier.
bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
@@ -2589,6 +2667,13 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParsedAttributesViewWithRange FnAttrs;
// Optional C++11 attribute-specifier
MaybeParseCXX11Attributes(attrs);
+
+ // The next token may be an OpenMP pragma annotation token. That would
+ // normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in
+ // this case, it came from an *attribute* rather than a pragma. Handle it now.
+ if (Tok.is(tok::annot_attr_openmp))
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
+
// We need to keep these attributes for future diagnostic
// before they are taken over by declaration specifier.
FnAttrs.addAll(attrs.begin(), attrs.end());
@@ -2597,8 +2682,6 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
MaybeParseMicrosoftAttributes(attrs);
if (Tok.is(tok::kw_using)) {
- ProhibitAttributes(attrs);
-
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
@@ -2617,7 +2700,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SourceLocation DeclEnd;
// Otherwise, it must be a using-declaration or an alias-declaration.
return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo,
- UsingLoc, DeclEnd, AS);
+ UsingLoc, DeclEnd, attrs, AS);
}
// Hold late-parsed attributes so we can attach a Decl to them later.
@@ -2733,8 +2816,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
else if (KW.is(tok::kw_delete))
DefinitionKind = FunctionDefinitionKind::Deleted;
else if (KW.is(tok::code_completion)) {
- Actions.CodeCompleteAfterFunctionEquals(DeclaratorInfo);
cutOffParsing();
+ Actions.CodeCompleteAfterFunctionEquals(DeclaratorInfo);
return nullptr;
}
}
@@ -2872,8 +2955,13 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
HasStaticInitializer = true;
}
+ if (PureSpecLoc.isValid() && VS.getAbstractLoc().isValid()) {
+ Diag(PureSpecLoc, diag::err_duplicate_virt_specifier) << "abstract";
+ }
if (ThisDecl && PureSpecLoc.isValid())
Actions.ActOnPureSpecifier(ThisDecl, PureSpecLoc);
+ else if (ThisDecl && VS.getAbstractLoc().isValid())
+ Actions.ActOnPureSpecifier(ThisDecl, VS.getAbstractLoc());
// Handle the initializer.
if (HasInClassInit != ICIS_NoInit) {
@@ -3180,6 +3268,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
return nullptr;
}
+ case tok::annot_attr_openmp:
case tok::annot_pragma_openmp:
return ParseOpenMPDeclarativeDirectiveWithExtDecl(
AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl);
@@ -3258,30 +3347,53 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
SourceLocation FinalLoc;
+ SourceLocation AbstractLoc;
bool IsFinalSpelledSealed = false;
+ bool IsAbstract = false;
// Parse the optional 'final' keyword.
if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
- VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok);
- assert((Specifier == VirtSpecifiers::VS_Final ||
- Specifier == VirtSpecifiers::VS_GNU_Final ||
- Specifier == VirtSpecifiers::VS_Sealed) &&
+ while (true) {
+ VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok);
+ if (Specifier == VirtSpecifiers::VS_None)
+ break;
+ if (isCXX11FinalKeyword()) {
+ if (FinalLoc.isValid()) {
+ auto Skipped = ConsumeToken();
+ Diag(Skipped, diag::err_duplicate_class_virt_specifier)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ } else {
+ FinalLoc = ConsumeToken();
+ if (Specifier == VirtSpecifiers::VS_Sealed)
+ IsFinalSpelledSealed = true;
+ }
+ } else {
+ if (AbstractLoc.isValid()) {
+ auto Skipped = ConsumeToken();
+ Diag(Skipped, diag::err_duplicate_class_virt_specifier)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ } else {
+ AbstractLoc = ConsumeToken();
+ IsAbstract = true;
+ }
+ }
+ if (TagType == DeclSpec::TST_interface)
+ Diag(FinalLoc, diag::err_override_control_interface)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ else if (Specifier == VirtSpecifiers::VS_Final)
+ Diag(FinalLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_override_control_keyword
+ : diag::ext_override_control_keyword)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ else if (Specifier == VirtSpecifiers::VS_Sealed)
+ Diag(FinalLoc, diag::ext_ms_sealed_keyword);
+ else if (Specifier == VirtSpecifiers::VS_Abstract)
+ Diag(AbstractLoc, diag::ext_ms_abstract_keyword);
+ else if (Specifier == VirtSpecifiers::VS_GNU_Final)
+ Diag(FinalLoc, diag::ext_warn_gnu_final);
+ }
+ assert((FinalLoc.isValid() || AbstractLoc.isValid()) &&
"not a class definition");
- FinalLoc = ConsumeToken();
- IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed;
-
- if (TagType == DeclSpec::TST_interface)
- Diag(FinalLoc, diag::err_override_control_interface)
- << VirtSpecifiers::getSpecifierName(Specifier);
- else if (Specifier == VirtSpecifiers::VS_Final)
- Diag(FinalLoc, getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_override_control_keyword
- : diag::ext_override_control_keyword)
- << VirtSpecifiers::getSpecifierName(Specifier);
- else if (Specifier == VirtSpecifiers::VS_Sealed)
- Diag(FinalLoc, diag::ext_ms_sealed_keyword);
- else if (Specifier == VirtSpecifiers::VS_GNU_Final)
- Diag(FinalLoc, diag::ext_warn_gnu_final);
// Parse any C++11 attributes after 'final' keyword.
// These attributes are not allowed to appear here,
@@ -3354,7 +3466,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl)
Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc,
- IsFinalSpelledSealed,
+ IsFinalSpelledSealed, IsAbstract,
T.getOpenLocation());
// C++ 11p3: Members of a class defined with the keyword class are private
@@ -3401,15 +3513,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// declarations and the lexed inline method definitions, along with any
// delayed attributes.
- // Save the state of Sema.FPFeatures, and change the setting
- // to the levels specified on the command line. Previous level
- // will be restored when the RAII object is destroyed.
- Sema::FPFeaturesStateRAII SaveFPFeaturesState(Actions);
- FPOptionsOverride NewOverrides;
- Actions.CurFPFeatures = NewOverrides.applyOverrides(getLangOpts());
- Actions.FpPragmaStack.Act(Tok.getLocation(), Sema::PSK_Reset, StringRef(),
- {} /*unused*/);
-
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedPragmas(getCurrentClass());
ParseLexedAttributes(getCurrentClass());
@@ -3491,9 +3594,10 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
do {
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
MemInitializers);
- return cutOffParsing();
+ return;
}
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
@@ -4039,6 +4143,70 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
}
}
+void Parser::ParseOpenMPAttributeArgs(IdentifierInfo *AttrName,
+ CachedTokens &OpenMPTokens) {
+ // Both 'sequence' and 'directive' attributes require arguments, so parse the
+ // open paren for the argument list.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ if (AttrName->isStr("directive")) {
+ // If the attribute is named `directive`, we can consume its argument list
+ // and push the tokens from it into the cached token stream for a new OpenMP
+ // pragma directive.
+ Token OMPBeginTok;
+ OMPBeginTok.startToken();
+ OMPBeginTok.setKind(tok::annot_attr_openmp);
+ OMPBeginTok.setLocation(Tok.getLocation());
+ OpenMPTokens.push_back(OMPBeginTok);
+
+ ConsumeAndStoreUntil(tok::r_paren, OpenMPTokens, /*StopAtSemi=*/false,
+ /*ConsumeFinalToken*/ false);
+ Token OMPEndTok;
+ OMPEndTok.startToken();
+ OMPEndTok.setKind(tok::annot_pragma_openmp_end);
+ OMPEndTok.setLocation(Tok.getLocation());
+ OpenMPTokens.push_back(OMPEndTok);
+ } else {
+ assert(AttrName->isStr("sequence") &&
+ "Expected either 'directive' or 'sequence'");
+ // If the attribute is named 'sequence', its argument is a list of one or
+ // more OpenMP attributes (either 'omp::directive' or 'omp::sequence',
+ // where the 'omp::' is optional).
+ do {
+ // We expect to see one of the following:
+ // * An identifier (omp) for the attribute namespace followed by ::
+ // * An identifier (directive) or an identifier (sequence).
+ SourceLocation IdentLoc;
+ IdentifierInfo *Ident = TryParseCXX11AttributeIdentifier(IdentLoc);
+
+ // If there is an identifier and it is 'omp', a double colon is required
+ // followed by the actual identifier we're after.
+ if (Ident && Ident->isStr("omp") && !ExpectAndConsume(tok::coloncolon))
+ Ident = TryParseCXX11AttributeIdentifier(IdentLoc);
+
+ // If we failed to find an identifier (scoped or otherwise), or we found
+ // an unexpected identifier, diagnose.
+ if (!Ident || (!Ident->isStr("directive") && !Ident->isStr("sequence"))) {
+ Diag(Tok.getLocation(), diag::err_expected_sequence_or_directive);
+ SkipUntil(tok::r_paren, StopBeforeMatch);
+ continue;
+ }
+ // We read an identifier. If the identifier is one of the ones we
+ // expected, we can recurse to parse the args.
+ ParseOpenMPAttributeArgs(Ident, OpenMPTokens);
+
+ // There may be a comma to signal that we expect another directive in the
+ // sequence.
+ } while (TryConsumeToken(tok::comma));
+ }
+ // Parse the closing paren for the argument list.
+ T.consumeClose();
+}
+
static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
IdentifierInfo *ScopeName) {
switch (
@@ -4079,7 +4247,8 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
ParsedAttributes &Attrs,
SourceLocation *EndLoc,
IdentifierInfo *ScopeName,
- SourceLocation ScopeLoc) {
+ SourceLocation ScopeLoc,
+ CachedTokens &OpenMPTokens) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
SourceLocation LParenLoc = Tok.getLocation();
const LangOptions &LO = getLangOpts();
@@ -4104,6 +4273,18 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
return true;
}
+ if (ScopeName && ScopeName->isStr("omp")) {
+ Diag(AttrNameLoc, getLangOpts().OpenMP >= 51
+ ? diag::warn_omp51_compat_attributes
+ : diag::ext_omp_attributes);
+
+ ParseOpenMPAttributeArgs(AttrName, OpenMPTokens);
+
+ // We claim that an attribute was parsed and added so that one is not
+ // created for us by the caller.
+ return true;
+ }
+
unsigned NumArgs;
// Some Clang-scoped attributes have some special parsing behavior.
if (ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")))
@@ -4163,11 +4344,12 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
///
/// [C++11] attribute-namespace:
/// identifier
-void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
- SourceLocation *endLoc) {
+void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
+ CachedTokens &OpenMPTokens,
+ SourceLocation *EndLoc) {
if (Tok.is(tok::kw_alignas)) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas);
- ParseAlignmentSpecifier(attrs, endLoc);
+ ParseAlignmentSpecifier(Attrs, EndLoc);
return;
}
@@ -4200,10 +4382,21 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs;
- while (Tok.isNot(tok::r_square)) {
- // attribute not present
- if (TryConsumeToken(tok::comma))
- continue;
+ bool AttrParsed = false;
+ while (!Tok.isOneOf(tok::r_square, tok::semi)) {
+ if (AttrParsed) {
+ // If we parsed an attribute, a comma is required before parsing any
+ // additional attributes.
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+ continue;
+ }
+ AttrParsed = false;
+ }
+
+ // Eat all remaining superfluous commas before parsing the next attribute.
+ while (TryConsumeToken(tok::comma))
+ ;
SourceLocation ScopeLoc, AttrLoc;
IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr;
@@ -4236,38 +4429,39 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
}
}
- bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName);
- bool AttrParsed = false;
-
- if (StandardAttr &&
- !SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second)
- Diag(AttrLoc, diag::err_cxx11_attribute_repeated)
- << AttrName << SourceRange(SeenAttrs[AttrName]);
-
// Parse attribute arguments
if (Tok.is(tok::l_paren))
- AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,
- ScopeName, ScopeLoc);
+ AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, OpenMPTokens);
- if (!AttrParsed)
- attrs.addNew(
+ if (!AttrParsed) {
+ Attrs.addNew(
AttrName,
SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc),
ScopeName, ScopeLoc, nullptr, 0,
getLangOpts().CPlusPlus ? ParsedAttr::AS_CXX11 : ParsedAttr::AS_C2x);
+ AttrParsed = true;
+ }
if (TryConsumeToken(tok::ellipsis))
Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
<< AttrName;
}
+ // If we hit an error and recovered by parsing up to a semicolon, eat the
+ // semicolon and don't issue further diagnostics about missing brackets.
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ return;
+ }
+
SourceLocation CloseLoc = Tok.getLocation();
if (ExpectAndConsume(tok::r_square))
SkipUntil(tok::r_square);
else if (Tok.is(tok::r_square))
checkCompoundToken(CloseLoc, tok::r_square, CompoundToken::AttrEnd);
- if (endLoc)
- *endLoc = Tok.getLocation();
+ if (EndLoc)
+ *EndLoc = Tok.getLocation();
if (ExpectAndConsume(tok::r_square))
SkipUntil(tok::r_square);
}
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 6acf76d713fd..22f3b7624c45 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -159,9 +159,9 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
/// Parse an expr that doesn't include (top-level) commas.
ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
- cutOffParsing();
return ExprError();
}
@@ -1156,9 +1156,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
ConsumeToken();
if (Tok.is(tok::code_completion) && &II != Ident_super) {
+ cutOffParsing();
Actions.CodeCompleteObjCClassPropertyRefExpr(
getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc);
- cutOffParsing();
return ExprError();
}
// Allow either an identifier or the keyword 'class' (in C++).
@@ -1469,6 +1469,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
case tok::kw_this:
Res = ParseCXXThis();
break;
+ case tok::kw___builtin_sycl_unique_stable_name:
+ Res = ParseSYCLUniqueStableNameExpression();
+ break;
case tok::annot_typename:
if (isStartOfObjCClassMessageMissingOpenBracket()) {
@@ -1724,9 +1727,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
Res = ParseBlockLiteralExpression();
break;
case tok::code_completion: {
+ cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
- cutOffParsing();
return ExprError();
}
case tok::l_square:
@@ -1807,7 +1810,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// These can be followed by postfix-expr pieces.
PreferredType = SavedType;
Res = ParsePostfixExpressionSuffix(Res);
- if (getLangOpts().OpenCL)
+ if (getLangOpts().OpenCL &&
+ !getActions().getOpenCLOptions().isAvailableOption(
+ "__cl_clang_function_pointers", getLangOpts()))
if (Expr *PostfixExpr = Res.get()) {
QualType Ty = PostfixExpr->getType();
if (!Ty.isNull() && Ty->isFunctionType()) {
@@ -1854,9 +1859,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (InMessageExpression)
return LHS;
+ cutOffParsing();
Actions.CodeCompletePostfixExpression(
getCurScope(), LHS, PreferredType.get(Tok.getLocation()));
- cutOffParsing();
return ExprError();
case tok::identifier:
@@ -2138,12 +2143,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
CorrectedBase = Base;
// Code completion for a member access expression.
+ cutOffParsing();
Actions.CodeCompleteMemberReferenceExpr(
getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow,
Base && ExprStatementTokLoc == Base->getBeginLoc(),
PreferredType.get(Tok.getLocation()));
- cutOffParsing();
return ExprError();
}
@@ -2322,6 +2327,33 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
return Operand;
}
+/// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id as
+/// a parameter.
+ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
+ assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) &&
+ "Not __bulitin_sycl_unique_stable_name");
+
+ SourceLocation OpLoc = ConsumeToken();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+
+ // __builtin_sycl_unique_stable_name expressions are always parenthesized.
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ "__builtin_sycl_unique_stable_name"))
+ return ExprError();
+
+ TypeResult Ty = ParseTypeName();
+
+ if (Ty.isInvalid()) {
+ T.skipToEnd();
+ return ExprError();
+ }
+
+ if (T.consumeClose())
+ return ExprError();
+
+ return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(),
+ T.getCloseLocation(), Ty.get());
+}
/// Parse a sizeof or alignof expression.
///
@@ -2776,10 +2808,10 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
CastTy = nullptr;
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteExpression(
getCurScope(), PreferredType.get(Tok.getLocation()),
/*IsParenthesized=*/ExprType >= CompoundLiteral);
- cutOffParsing();
return ExprError();
}
@@ -3410,8 +3442,9 @@ Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
/// \endverbatim
void Parser::ParseBlockId(SourceLocation CaretLoc) {
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
- return cutOffParsing();
+ return;
}
// Parse the specifier-qualifier-list piece.
@@ -3596,8 +3629,8 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
} else {
// Parse the platform name.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteAvailabilityPlatformName();
cutOffParsing();
+ Actions.CodeCompleteAvailabilityPlatformName();
return None;
}
if (Tok.isNot(tok::identifier)) {
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 4b5703d79f28..f3d10b4a0889 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -9,7 +9,6 @@
// This file implements the Expression parsing implementation for C++.
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/Parser.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
@@ -17,6 +16,7 @@
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -235,6 +235,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
while (true) {
if (HasScopeSpecifier) {
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
// Code completion for a nested-name-specifier, where the code
// completion token follows the '::'.
Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext,
@@ -245,7 +246,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
// token will cause assertion in
// Preprocessor::AnnotatePreviousCachedTokens.
SS.setEndLoc(Tok.getLocation());
- cutOffParsing();
return true;
}
@@ -688,9 +688,9 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/// ParseLambdaExpression - Parse a C++11 lambda expression.
///
/// lambda-expression:
-/// lambda-introducer lambda-declarator[opt] compound-statement
+/// lambda-introducer lambda-declarator compound-statement
/// lambda-introducer '<' template-parameter-list '>'
-/// lambda-declarator[opt] compound-statement
+/// requires-clause[opt] lambda-declarator compound-statement
///
/// lambda-introducer:
/// '[' lambda-capture[opt] ']'
@@ -722,9 +722,13 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/// '&' identifier initializer
///
/// lambda-declarator:
-/// '(' parameter-declaration-clause ')' attribute-specifier[opt]
-/// 'mutable'[opt] exception-specification[opt]
-/// trailing-return-type[opt]
+/// lambda-specifiers [C++2b]
+/// '(' parameter-declaration-clause ')' lambda-specifiers
+/// requires-clause[opt]
+///
+/// lambda-specifiers:
+/// decl-specifier-seq[opt] noexcept-specifier[opt]
+/// attribute-specifier-seq[opt] trailing-return-type[opt]
///
ExprResult Parser::ParseLambdaExpression() {
// Parse lambda-introducer.
@@ -877,9 +881,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// expression parser perform the completion.
if (Tok.is(tok::code_completion) &&
!(getLangOpts().ObjC && Tentative)) {
+ cutOffParsing();
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/false);
- cutOffParsing();
break;
}
@@ -891,6 +895,7 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
}
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
// If we're in Objective-C++ and we have a bare '[', then this is more
// likely to be a message receiver.
if (getLangOpts().ObjC && Tentative && First)
@@ -898,7 +903,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
else
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/false);
- cutOffParsing();
break;
}
@@ -943,9 +947,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
ConsumeToken();
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/true);
- cutOffParsing();
break;
}
}
@@ -1249,7 +1253,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Actions.PushLambdaScope();
ParsedAttributes Attr(AttrFactory);
- SourceLocation DeclLoc = Tok.getLocation();
if (getLangOpts().CUDA) {
// In CUDA code, GNU attributes are allowed to appear immediately after the
// "[...]", even if there is no "(...)" before the lambda body.
@@ -1302,13 +1305,99 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
}
}
+ // Implement WG21 P2173, which allows attributes immediately before the
+ // lambda declarator and applies them to the corresponding function operator
+ // or operator template declaration. We accept this as a conforming extension
+ // in all language modes that support lambdas.
+ if (isCXX11AttributeSpecifier()) {
+ Diag(Tok, getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx20_compat_decl_attrs_on_lambda
+ : diag::ext_decl_attrs_on_lambda);
+ MaybeParseCXX11Attributes(D);
+ }
+
TypeResult TrailingReturnType;
SourceLocation TrailingReturnTypeLoc;
+
+ auto ParseLambdaSpecifiers =
+ [&](SourceLocation LParenLoc, SourceLocation RParenLoc,
+ MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
+ SourceLocation EllipsisLoc) {
+ SourceLocation DeclEndLoc = RParenLoc;
+
+ // GNU-style attributes must be parsed before the mutable specifier to
+ // be compatible with GCC. MSVC-style attributes must be parsed before
+ // the mutable specifier to be compatible with MSVC.
+ MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
+
+ // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
+ // the DeclEndLoc.
+ SourceLocation MutableLoc;
+ SourceLocation ConstexprLoc;
+ SourceLocation ConstevalLoc;
+ tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
+ ConstevalLoc, DeclEndLoc);
+
+ addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
+ addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+ // Parse exception-specification[opt].
+ ExceptionSpecificationType ESpecType = EST_None;
+ SourceRange ESpecRange;
+ SmallVector<ParsedType, 2> DynamicExceptions;
+ SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens;
+ ESpecType = tryParseExceptionSpecification(
+ /*Delayed=*/false, ESpecRange, DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens);
+
+ if (ESpecType != EST_None)
+ DeclEndLoc = ESpecRange.getEnd();
+
+ // Parse attribute-specifier[opt].
+ 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].
+ if (Tok.is(tok::arrow)) {
+ FunLocalRangeEnd = Tok.getLocation();
+ SourceRange Range;
+ TrailingReturnType = ParseTrailingReturnType(
+ Range, /*MayBeFollowedByDirectInit*/ false);
+ TrailingReturnTypeLoc = Range.getBegin();
+ if (Range.getEnd().isValid())
+ DeclEndLoc = Range.getEnd();
+ }
+
+ SourceLocation NoLoc;
+ D.AddTypeInfo(
+ DeclaratorChunk::getFunction(
+ /*HasProto=*/true,
+ /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
+ ParamInfo.size(), EllipsisLoc, RParenLoc,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange,
+ DynamicExceptions.data(), DynamicExceptionRanges.data(),
+ DynamicExceptions.size(),
+ NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
+ /*ExceptionSpecTokens*/ nullptr,
+ /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
+ TrailingReturnType, TrailingReturnTypeLoc, &DS),
+ std::move(Attr), DeclEndLoc);
+ };
+
if (Tok.is(tok::l_paren)) {
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope |
- Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -1334,170 +1423,36 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
}
T.consumeClose();
- SourceLocation RParenLoc = T.getCloseLocation();
- SourceLocation DeclEndLoc = RParenLoc;
-
- // GNU-style attributes must be parsed before the mutable specifier to be
- // compatible with GCC.
- MaybeParseGNUAttributes(Attr, &DeclEndLoc);
-
- // MSVC-style attributes must be parsed before the mutable specifier to be
- // compatible with MSVC.
- MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc);
-
- // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the
- // DeclEndLoc.
- SourceLocation MutableLoc;
- SourceLocation ConstexprLoc;
- SourceLocation ConstevalLoc;
- tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
- ConstevalLoc, DeclEndLoc);
-
- addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
- addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
- // Parse exception-specification[opt].
- ExceptionSpecificationType ESpecType = EST_None;
- SourceRange ESpecRange;
- SmallVector<ParsedType, 2> DynamicExceptions;
- SmallVector<SourceRange, 2> DynamicExceptionRanges;
- ExprResult NoexceptExpr;
- CachedTokens *ExceptionSpecTokens;
- ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
- ESpecRange,
- DynamicExceptions,
- DynamicExceptionRanges,
- NoexceptExpr,
- ExceptionSpecTokens);
-
- if (ESpecType != EST_None)
- DeclEndLoc = ESpecRange.getEnd();
-
- // Parse attribute-specifier[opt].
- 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].
- if (Tok.is(tok::arrow)) {
- FunLocalRangeEnd = Tok.getLocation();
- SourceRange Range;
- TrailingReturnType =
- ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
- TrailingReturnTypeLoc = Range.getBegin();
- if (Range.getEnd().isValid())
- DeclEndLoc = Range.getEnd();
- }
- SourceLocation NoLoc;
- D.AddTypeInfo(DeclaratorChunk::getFunction(
- /*HasProto=*/true,
- /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
- ParamInfo.size(), EllipsisLoc, RParenLoc,
- /*RefQualifierIsLvalueRef=*/true,
- /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType,
- ESpecRange, DynamicExceptions.data(),
- DynamicExceptionRanges.data(), DynamicExceptions.size(),
- NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
- /*ExceptionSpecTokens*/ nullptr,
- /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
- TrailingReturnType, TrailingReturnTypeLoc, &DS),
- std::move(Attr), DeclEndLoc);
+ // Parse lambda-specifiers.
+ ParseLambdaSpecifiers(LParenLoc, /*DeclEndLoc=*/T.getCloseLocation(),
+ ParamInfo, EllipsisLoc);
// 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___private, tok::kw___global, tok::kw___local,
tok::kw___constant, tok::kw___generic,
- tok::kw_requires) ||
+ tok::kw_requires, tok::kw_noexcept) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
- // It's common to forget that one needs '()' before 'mutable', an attribute
- // 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");
- }
-
- Diag(Tok, diag::err_lambda_missing_parens)
- << TokKind
- << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
- SourceLocation DeclEndLoc = DeclLoc;
-
- // GNU-style attributes must be parsed before the mutable specifier to be
- // compatible with GCC.
- MaybeParseGNUAttributes(Attr, &DeclEndLoc);
-
- // Parse 'mutable', if it's there.
- SourceLocation MutableLoc;
- if (Tok.is(tok::kw_mutable)) {
- MutableLoc = ConsumeToken();
- DeclEndLoc = MutableLoc;
- }
-
- // Parse attribute-specifier[opt].
- MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
-
- // Parse the return type, if there is one.
- if (Tok.is(tok::arrow)) {
- SourceRange Range;
- TrailingReturnType =
- ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
- if (Range.getEnd().isValid())
- DeclEndLoc = Range.getEnd();
- }
+ if (!getLangOpts().CPlusPlus2b)
+ // It's common to forget that one needs '()' before 'mutable', an
+ // attribute specifier, the result type, or the requires clause. Deal with
+ // this.
+ Diag(Tok, diag::ext_lambda_missing_parens)
+ << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
SourceLocation NoLoc;
- D.AddTypeInfo(DeclaratorChunk::getFunction(
- /*HasProto=*/true,
- /*IsAmbiguous=*/false,
- /*LParenLoc=*/NoLoc,
- /*Params=*/nullptr,
- /*NumParams=*/0,
- /*EllipsisLoc=*/NoLoc,
- /*RParenLoc=*/NoLoc,
- /*RefQualifierIsLvalueRef=*/true,
- /*RefQualifierLoc=*/NoLoc, MutableLoc, EST_None,
- /*ESpecRange=*/SourceRange(),
- /*Exceptions=*/nullptr,
- /*ExceptionRanges=*/nullptr,
- /*NumExceptions=*/0,
- /*NoexceptExpr=*/nullptr,
- /*ExceptionSpecTokens=*/nullptr,
- /*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();
+ // Parse lambda-specifiers.
+ std::vector<DeclaratorChunk::ParamInfo> EmptyParamInfo;
+ ParseLambdaSpecifiers(/*LParenLoc=*/NoLoc, /*RParenLoc=*/NoLoc,
+ EmptyParamInfo, /*EllipsisLoc=*/NoLoc);
}
+ WarnIfHasCUDATargetAttr();
+
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
// it.
unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
@@ -1979,17 +1934,36 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// \param FRI If non-null, a for range declaration is permitted, and if
/// present will be parsed and stored here, and a null result will be returned.
///
+/// \param EnterForConditionScope If true, enter a continue/break scope at the
+/// appropriate moment for a 'for' loop.
+///
/// \returns The parsed condition.
Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
SourceLocation Loc,
Sema::ConditionKind CK,
- ForRangeInfo *FRI) {
+ ForRangeInfo *FRI,
+ bool EnterForConditionScope) {
+ // Helper to ensure we always enter a continue/break scope if requested.
+ struct ForConditionScopeRAII {
+ Scope *S;
+ void enter(bool IsConditionVariable) {
+ if (S) {
+ S->AddFlags(Scope::BreakScope | Scope::ContinueScope);
+ S->setIsConditionVarScope(IsConditionVariable);
+ }
+ }
+ ~ForConditionScopeRAII() {
+ if (S)
+ S->setIsConditionVarScope(false);
+ }
+ } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr};
+
ParenBraceBracketBalancer BalancerRAIIObj(*this);
PreferredType.enterCondition(Actions, Tok.getLocation());
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
cutOffParsing();
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
return Sema::ConditionError();
}
@@ -2006,6 +1980,9 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
// Determine what kind of thing we have.
switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) {
case ConditionOrInitStatement::Expression: {
+ // If this is a for loop, we're entering its condition.
+ ForConditionScope.enter(/*IsConditionVariable=*/false);
+
ProhibitAttributes(attrs);
// We can have an empty expression here.
@@ -2048,11 +2025,16 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
}
case ConditionOrInitStatement::ForRangeDecl: {
+ // This is 'for (init-stmt; for-range-decl : range-expr)'.
+ // We're not actually in a for loop yet, so 'break' and 'continue' aren't
+ // permitted here.
assert(FRI && "should not parse a for range declaration here");
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy DG = ParseSimpleDeclaration(DeclaratorContext::ForInit,
DeclEnd, attrs, false, FRI);
FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
+ assert((FRI->ColonLoc.isValid() || !DG) &&
+ "cannot find for range declaration");
return Sema::ConditionResult();
}
@@ -2061,6 +2043,9 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
break;
}
+ // If this is a for loop, we're entering its condition.
+ ForConditionScope.enter(/*IsConditionVariable=*/true);
+
// type-specifier-seq
DeclSpec DS(AttrFactory);
DS.takeAttributesFrom(attrs);
@@ -2600,10 +2585,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
}
case tok::code_completion: {
+ // Don't try to parse any further.
+ cutOffParsing();
// Code completion for the operator name.
Actions.CodeCompleteOperatorName(getCurScope());
- cutOffParsing();
- // Don't try to parse any further.
return true;
}
@@ -2651,9 +2636,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Grab the literal operator's suffix, which will be either the next token
// or a ud-suffix from the string literal.
+ bool IsUDSuffix = !Literal.getUDSuffix().empty();
IdentifierInfo *II = nullptr;
SourceLocation SuffixLoc;
- if (!Literal.getUDSuffix().empty()) {
+ if (IsUDSuffix) {
II = &PP.getIdentifierTable().get(Literal.getUDSuffix());
SuffixLoc =
Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
@@ -2690,7 +2676,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
- return Actions.checkLiteralOperatorId(SS, Result);
+ return Actions.checkLiteralOperatorId(SS, Result, IsUDSuffix);
}
// Parse a conversion-function-id.
diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp
index 9ac2b2e6f79b..9d9c03d28a97 100644
--- a/clang/lib/Parse/ParseInit.cpp
+++ b/clang/lib/Parse/ParseInit.cpp
@@ -159,8 +159,7 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
///
/// \p CodeCompleteCB is called with Designation parsed so far.
ExprResult Parser::ParseInitializerWithPotentialDesignator(
- llvm::function_ref<void(const Designation &)> CodeCompleteCB) {
-
+ DesignatorCompletionInfo DesignatorCompletion) {
// If this is the old-style GNU extension:
// designation ::= identifier ':'
// Handle it as a field designator. Otherwise, this must be the start of a
@@ -183,6 +182,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator(
Designation D;
D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
+ PreferredType.enterDesignatedInitializer(
+ Tok.getLocation(), DesignatorCompletion.PreferredBaseType, D);
return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
ParseInitializer());
}
@@ -199,8 +200,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator(
SourceLocation DotLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
- CodeCompleteCB(Desig);
cutOffParsing();
+ Actions.CodeCompleteDesignator(DesignatorCompletion.PreferredBaseType,
+ DesignatorCompletion.InitExprs, Desig);
return ExprError();
}
if (Tok.isNot(tok::identifier)) {
@@ -388,6 +390,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator(
// Handle a normal designator sequence end, which is an equal.
if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
+ PreferredType.enterDesignatedInitializer(
+ Tok.getLocation(), DesignatorCompletion.PreferredBaseType, Desig);
return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,
ParseInitializer());
}
@@ -396,6 +400,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator(
// direct-list-initialization of the aggregate element. We allow this as an
// extension from C++11 onwards (when direct-list-initialization was added).
if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
+ PreferredType.enterDesignatedInitializer(
+ Tok.getLocation(), DesignatorCompletion.PreferredBaseType, Desig);
return Actions.ActOnDesignatedInitializer(Desig, SourceLocation(), false,
ParseBraceInitializer());
}
@@ -453,9 +459,9 @@ ExprResult Parser::ParseBraceInitializer() {
Actions, EnterExpressionEvaluationContext::InitList);
bool InitExprsOk = true;
- auto CodeCompleteDesignation = [&](const Designation &D) {
- Actions.CodeCompleteDesignator(PreferredType.get(T.getOpenLocation()),
- InitExprs, D);
+ DesignatorCompletionInfo DesignatorCompletion{
+ InitExprs,
+ PreferredType.get(T.getOpenLocation()),
};
while (1) {
@@ -476,7 +482,7 @@ ExprResult Parser::ParseBraceInitializer() {
// initializer directly.
ExprResult SubElt;
if (MayBeDesignationStart())
- SubElt = ParseInitializerWithPotentialDesignator(CodeCompleteDesignation);
+ SubElt = ParseInitializerWithPotentialDesignator(DesignatorCompletion);
else
SubElt = ParseInitializer();
@@ -556,9 +562,9 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
return false;
}
- auto CodeCompleteDesignation = [&](const Designation &D) {
- Actions.CodeCompleteDesignator(PreferredType.get(Braces.getOpenLocation()),
- InitExprs, D);
+ DesignatorCompletionInfo DesignatorCompletion{
+ InitExprs,
+ PreferredType.get(Braces.getOpenLocation()),
};
while (!isEofOrEom()) {
trailingComma = false;
@@ -566,7 +572,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
// initializer directly.
ExprResult SubElt;
if (MayBeDesignationStart())
- SubElt = ParseInitializerWithPotentialDesignator(CodeCompleteDesignation);
+ SubElt = ParseInitializerWithPotentialDesignator(DesignatorCompletion);
else
SubElt = ParseInitializer();
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 88942ed173d0..9e145f57d61f 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -50,8 +50,8 @@ Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) {
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCAtDirective(getCurScope());
return nullptr;
}
@@ -219,8 +219,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Code completion after '@interface'.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
return nullptr;
}
@@ -253,8 +253,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
SourceLocation categoryLoc;
IdentifierInfo *categoryId = nullptr;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
+ Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
return nullptr;
}
@@ -308,8 +308,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Code completion of superclass names.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
cutOffParsing();
+ Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
return nullptr;
}
@@ -472,8 +472,8 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
if (Tok.is(tok::code_completion)) {
// FIXME: If these aren't protocol references, we'll need different
// completions.
- Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
cutOffParsing();
+ Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
// FIXME: Better recovery here?.
return nullptr;
@@ -635,10 +635,11 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// Code completion within an Objective-C interface.
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
CurParsedObjCImpl? Sema::PCC_ObjCImplementation
: Sema::PCC_ObjCInterface);
- return cutOffParsing();
+ return;
}
// If we don't have an @ directive, parse it as a function definition.
@@ -668,8 +669,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// Otherwise, we have an @ directive, eat the @.
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCAtDirective(getCurScope());
- return cutOffParsing();
+ return;
}
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
@@ -778,8 +780,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// We break out of the big loop in two cases: when we see @end or when we see
// EOF. In the former case, eat the @end. In the later case, emit an error.
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCAtDirective(getCurScope());
- return cutOffParsing();
+ return;
} else if (Tok.isObjCAtKeyword(tok::objc_end)) {
ConsumeToken(); // the "end" identifier
} else {
@@ -847,8 +850,9 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
while (1) {
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
- return cutOffParsing();
+ return;
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -893,11 +897,12 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
}
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
if (IsSetter)
Actions.CodeCompleteObjCPropertySetter(getCurScope());
else
Actions.CodeCompleteObjCPropertyGetter(getCurScope());
- return cutOffParsing();
+ return;
}
SourceLocation SelLoc;
@@ -1146,9 +1151,10 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
while (1) {
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCPassingType(
getCurScope(), DS, Context == DeclaratorContext::ObjCParameter);
- return cutOffParsing();
+ return;
}
if (Tok.isNot(tok::identifier))
@@ -1335,9 +1341,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
/*ReturnType=*/nullptr);
- cutOffParsing();
return nullptr;
}
@@ -1350,14 +1356,13 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the method, parse them.
ParsedAttributes methodAttrs(AttrFactory);
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(methodAttrs);
- MaybeParseCXX11Attributes(methodAttrs);
+ MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
+ methodAttrs);
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
ReturnType);
- cutOffParsing();
return nullptr;
}
@@ -1377,9 +1382,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(methodAttrs);
- MaybeParseCXX11Attributes(methodAttrs);
+ MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
+ methodAttrs);
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
Decl *Result = Actions.ActOnMethodDeclaration(
@@ -1412,19 +1416,18 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the argument name, parse them.
// Regardless, collect all the attributes we've parsed so far.
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(paramAttrs);
- MaybeParseCXX11Attributes(paramAttrs);
+ MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
+ paramAttrs);
ArgInfo.ArgAttrs = paramAttrs;
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
KeyIdents.push_back(SelIdent);
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/true,
ReturnType, KeyIdents);
- cutOffParsing();
return nullptr;
}
@@ -1444,11 +1447,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/false,
ReturnType, KeyIdents);
- cutOffParsing();
return nullptr;
}
@@ -1496,9 +1499,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// FIXME: Add support for optional parameter list...
// If attributes exist after the method, parse them.
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(methodAttrs);
- MaybeParseCXX11Attributes(methodAttrs);
+ MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
+ methodAttrs);
if (KeyIdents.size() == 0)
return nullptr;
@@ -1531,8 +1533,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
while (1) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
cutOffParsing();
+ Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
return true;
}
@@ -1630,12 +1632,12 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers(
}
QualType BaseT = Actions.GetTypeFromParser(baseType);
+ cutOffParsing();
if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
} else {
Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
}
- cutOffParsing();
return;
}
@@ -1924,8 +1926,9 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
// Set the default visibility to private.
if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteObjCAtVisibility(getCurScope());
- return cutOffParsing();
+ return;
}
switch (Tok.getObjCKeywordID()) {
@@ -1954,9 +1957,10 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
}
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
Sema::PCC_ObjCInstanceVariableList);
- return cutOffParsing();
+ return;
}
// This needs to duplicate a small amount of code from
@@ -2021,8 +2025,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
ConsumeToken(); // the "protocol" identifier
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCProtocolDecl(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCProtocolDecl(getCurScope());
return nullptr;
}
@@ -2105,8 +2109,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
// Code completion after '@implementation'.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCImplementationDecl(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCImplementationDecl(getCurScope());
return nullptr;
}
@@ -2143,8 +2147,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
IdentifierInfo *categoryId = nullptr;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
+ Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
return nullptr;
}
@@ -2313,8 +2317,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
return nullptr;
}
@@ -2331,8 +2335,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
if (TryConsumeToken(tok::equal)) {
// property '=' ivar-name
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
cutOffParsing();
+ Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
return nullptr;
}
@@ -2391,8 +2395,8 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
return nullptr;
}
@@ -2728,8 +2732,8 @@ Decl *Parser::ParseObjCMethodDefinition() {
StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
ParsedStmtContext StmtCtx) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtStatement(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCAtStatement(getCurScope());
return StmtError();
}
@@ -2769,8 +2773,8 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
case tok::code_completion:
- Actions.CodeCompleteObjCAtExpression(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCAtExpression(getCurScope());
return ExprError();
case tok::minus:
@@ -3016,8 +3020,8 @@ ExprResult Parser::ParseObjCMessageExpression() {
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCMessageReceiver(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteObjCMessageReceiver(getCurScope());
return ExprError();
}
@@ -3153,6 +3157,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
InMessageExpressionRAIIObject InMessage(*this, true);
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
false);
@@ -3162,7 +3167,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
None, false);
- cutOffParsing();
return ExprError();
}
@@ -3191,6 +3195,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
/// Parse the expression after ':'
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
KeyIdents,
@@ -3204,7 +3209,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents,
/*AtArgumentExpression=*/true);
- cutOffParsing();
return ExprError();
}
@@ -3229,6 +3233,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Code completion after each argument.
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
KeyIdents,
@@ -3241,7 +3246,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
KeyIdents,
/*AtArgumentExpression=*/false);
- cutOffParsing();
return ExprError();
}
@@ -3581,8 +3585,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
ConsumeParen();
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
+ Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
return ExprError();
}
@@ -3607,8 +3611,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
break;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
+ Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
return ExprError();
}
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index db7e967b15ae..18e43c3734ac 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -131,6 +131,7 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {
{OMPD_declare, OMPD_simd, OMPD_declare_simd},
{OMPD_declare, OMPD_target, OMPD_declare_target},
{OMPD_declare, OMPD_variant, OMPD_declare_variant},
+ {OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target},
{OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant},
{OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant},
{OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},
@@ -441,9 +442,9 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
ConsumeToken();
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm);
Actions.FinalizeDeclaration(OmpPrivParm);
- cutOffParsing();
return;
}
@@ -1664,30 +1665,41 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {
return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc);
}
-Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
- // OpenMP 4.5 syntax with list of entities.
- Sema::NamedDeclSetType SameDirectiveDecls;
- SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation,
- NamedDecl *>,
- 4>
- DeclareTargetDecls;
- OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any;
+void Parser::ParseOMPDeclareTargetClauses(
+ Sema::DeclareTargetContextInfo &DTCI) {
SourceLocation DeviceTypeLoc;
+ bool RequiresToOrLinkClause = false;
+ bool HasToOrLinkClause = false;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;
- if (Tok.is(tok::identifier)) {
+ bool HasIdentifier = Tok.is(tok::identifier);
+ if (HasIdentifier) {
+ // If we see any clause we need a to or link clause.
+ RequiresToOrLinkClause = true;
IdentifierInfo *II = Tok.getIdentifierInfo();
StringRef ClauseName = II->getName();
bool IsDeviceTypeClause =
getLangOpts().OpenMP >= 50 &&
getOpenMPClauseKind(ClauseName) == OMPC_device_type;
- // Parse 'to|link|device_type' clauses.
- if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) &&
- !IsDeviceTypeClause) {
+
+ bool IsToOrLinkClause =
+ OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT);
+ assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!");
+
+ if (!IsDeviceTypeClause && DTCI.Kind == OMPD_begin_declare_target) {
Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
- << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0);
+ << ClauseName << 0;
break;
}
+ if (!IsDeviceTypeClause && !IsToOrLinkClause) {
+ Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
+ << ClauseName << (getLangOpts().OpenMP >= 50 ? 2 : 1);
+ break;
+ }
+
+ if (IsToOrLinkClause)
+ HasToOrLinkClause = true;
+
// Parse 'device_type' clause and go to next clause if any.
if (IsDeviceTypeClause) {
Optional<SimpleClauseData> DevTypeData =
@@ -1697,16 +1709,17 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
// We already saw another device_type clause, diagnose it.
Diag(DevTypeData.getValue().Loc,
diag::warn_omp_more_one_device_type_clause);
+ break;
}
switch (static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) {
case OMPC_DEVICE_TYPE_any:
- DT = OMPDeclareTargetDeclAttr::DT_Any;
+ DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any;
break;
case OMPC_DEVICE_TYPE_host:
- DT = OMPDeclareTargetDeclAttr::DT_Host;
+ DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host;
break;
case OMPC_DEVICE_TYPE_nohost:
- DT = OMPDeclareTargetDeclAttr::DT_NoHost;
+ DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost;
break;
case OMPC_DEVICE_TYPE_unknown:
llvm_unreachable("Unexpected device_type");
@@ -1717,37 +1730,47 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
}
ConsumeToken();
}
- auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls](
- CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
- NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName(
- getCurScope(), SS, NameInfo, SameDirectiveDecls);
- if (ND)
- DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND);
- };
- if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,
- /*AllowScopeSpecifier=*/true))
+
+ if (DTCI.Kind == OMPD_declare_target || HasIdentifier) {
+ auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS,
+ DeclarationNameInfo NameInfo) {
+ NamedDecl *ND =
+ Actions.lookupOpenMPDeclareTargetName(getCurScope(), SS, NameInfo);
+ if (!ND)
+ return;
+ Sema::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()};
+ bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second;
+ if (!FirstMapping)
+ Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple)
+ << NameInfo.getName();
+ };
+ if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,
+ /*AllowScopeSpecifier=*/true))
+ break;
+ }
+
+ if (Tok.is(tok::l_paren)) {
+ Diag(Tok,
+ diag::err_omp_begin_declare_target_unexpected_implicit_to_clause);
+ break;
+ }
+ if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok,
+ diag::err_omp_declare_target_unexpected_clause_after_implicit_to);
break;
+ }
// Consume optional ','.
if (Tok.is(tok::comma))
ConsumeToken();
}
+
+ // For declare target require at least 'to' or 'link' to be present.
+ if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkClause &&
+ !HasToOrLinkClause)
+ Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause);
+
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
- ConsumeAnyToken();
- for (auto &MTLocDecl : DeclareTargetDecls) {
- OMPDeclareTargetDeclAttr::MapTypeTy MT;
- SourceLocation Loc;
- NamedDecl *ND;
- std::tie(MT, Loc, ND) = MTLocDecl;
- // device_type clause is applied only to functions.
- Actions.ActOnOpenMPDeclareTargetName(
- ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT);
- }
- SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(),
- SameDirectiveDecls.end());
- if (Decls.empty())
- return DeclGroupPtrTy();
- return Actions.BuildDeclaratorGroup(Decls);
}
void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) {
@@ -1784,10 +1807,11 @@ void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind,
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
-void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
+void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind,
+ OpenMPDirectiveKind EndDKind,
SourceLocation DKLoc) {
- parseOMPEndDirective(OMPD_declare_target, OMPD_end_declare_target, DKind,
- DKLoc, Tok.getLocation(),
+ parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc,
+ Tok.getLocation(),
/* SkipUntilOpenMPEnd */ false);
// Skip the last annot_pragma_openmp_end.
if (Tok.is(tok::annot_pragma_openmp_end))
@@ -1833,7 +1857,8 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed,
DeclSpec::TST TagType, Decl *Tag) {
- assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&
+ "Not an OpenMP directive!");
ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -1851,7 +1876,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
Toks.push_back(Tok);
while (Cnt && Tok.isNot(tok::eof)) {
(void)ConsumeAnyToken();
- if (Tok.is(tok::annot_pragma_openmp))
+ if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp))
++Cnt;
else if (Tok.is(tok::annot_pragma_openmp_end))
--Cnt;
@@ -2074,7 +2099,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ConsumeAnyToken();
DeclGroupPtrTy Ptr;
- if (Tok.is(tok::annot_pragma_openmp)) {
+ if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) {
Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,
TagType, Tag);
} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
@@ -2101,58 +2126,48 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ParseOMPDeclareVariantClauses(Ptr, Toks, Loc);
return Ptr;
}
+ case OMPD_begin_declare_target:
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
- if (Tok.isNot(tok::annot_pragma_openmp_end)) {
- return ParseOMPDeclareTargetClauses();
- }
+ bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);
+ bool HasImplicitMappings =
+ DKind == OMPD_begin_declare_target || !HasClauses;
+ Sema::DeclareTargetContextInfo DTCI(DKind, DTLoc);
+ if (HasClauses)
+ ParseOMPDeclareTargetClauses(DTCI);
// Skip the last annot_pragma_openmp_end.
ConsumeAnyToken();
- if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc))
- return DeclGroupPtrTy();
-
- ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
- llvm::SmallVector<Decl *, 4> Decls;
- DKind = parseOpenMPDirectiveKind(*this);
- while (DKind != OMPD_end_declare_target && Tok.isNot(tok::eof) &&
- Tok.isNot(tok::r_brace)) {
- DeclGroupPtrTy Ptr;
- // Here we expect to see some function declaration.
- if (AS == AS_none) {
- assert(TagType == DeclSpec::TST_unspecified);
- MaybeParseCXX11Attributes(Attrs);
- ParsingDeclSpec PDS(*this);
- Ptr = ParseExternalDeclaration(Attrs, &PDS);
- } else {
- Ptr =
- ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
- }
- if (Ptr) {
- DeclGroupRef Ref = Ptr.get();
- Decls.append(Ref.begin(), Ref.end());
- }
- if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
- TentativeParsingAction TPA(*this);
- ConsumeAnnotationToken();
- DKind = parseOpenMPDirectiveKind(*this);
- if (DKind != OMPD_end_declare_target)
- TPA.Revert();
- else
- TPA.Commit();
- }
+ if (HasImplicitMappings) {
+ Actions.ActOnStartOpenMPDeclareTargetContext(DTCI);
+ return nullptr;
}
- ParseOMPEndDeclareTargetDirective(DKind, DTLoc);
- Actions.ActOnFinishOpenMPDeclareTargetDirective();
+ Actions.ActOnFinishedOpenMPDeclareTargetContext(DTCI);
+ llvm::SmallVector<Decl *, 4> Decls;
+ for (auto &It : DTCI.ExplicitlyMapped)
+ Decls.push_back(It.first);
return Actions.BuildDeclaratorGroup(Decls);
}
+ case OMPD_end_declare_target: {
+ if (!Actions.isInOpenMPDeclareTargetContext()) {
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << 1 << getOpenMPDirectiveName(DKind);
+ break;
+ }
+ const Sema::DeclareTargetContextInfo &DTCI =
+ Actions.ActOnOpenMPEndDeclareTargetDirective();
+ ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc);
+ return nullptr;
+ }
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
case OMPD_parallel:
case OMPD_simd:
+ case OMPD_tile:
+ case OMPD_unroll:
case OMPD_task:
case OMPD_taskyield:
case OMPD_barrier:
@@ -2190,7 +2205,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_parallel_master_taskloop:
case OMPD_parallel_master_taskloop_simd:
case OMPD_distribute:
- case OMPD_end_declare_target:
case OMPD_target_update:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
@@ -2206,6 +2220,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
case OMPD_target_teams_distribute_simd:
+ case OMPD_dispatch:
+ case OMPD_masked:
Diag(Tok, diag::err_omp_unexpected_directive)
<< 1 << getOpenMPDirectiveName(DKind);
break;
@@ -2255,12 +2271,13 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/// 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}
+/// for simd' | 'target teams distribute simd' | 'masked' {clause}
/// annot_pragma_openmp_end
///
StmtResult
Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
- assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&
+ "Not an OpenMP directive!");
ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<OMPClause *, 5> Clauses;
@@ -2377,6 +2394,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
+ case OMPD_interop:
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
@@ -2387,6 +2405,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
LLVM_FALLTHROUGH;
case OMPD_parallel:
case OMPD_simd:
+ case OMPD_tile:
+ case OMPD_unroll:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
@@ -2427,7 +2447,9 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_target_teams_distribute_simd: {
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_dispatch:
+ case OMPD_masked: {
// Special processing for flush and depobj clauses.
Token ImplicitTok;
bool ImplicitClauseAllowed = false;
@@ -2521,6 +2543,11 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
HasAssociatedStatement = false;
}
+ if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) {
+ Diag(Loc, diag::err_omp_required_clause)
+ << getOpenMPDirectiveName(OMPD_tile) << "sizes";
+ }
+
StmtResult AssociatedStmt;
if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
@@ -2529,7 +2556,15 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
// the captured region. Code elsewhere assumes that any FunctionScopeInfo
// should have at least one compound statement scope within it.
ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
- AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement());
+ {
+ Sema::CompoundScopeRAII Scope(Actions);
+ AssociatedStmt = ParseStatement();
+
+ if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) &&
+ getLangOpts().OpenMPIRBuilder)
+ AssociatedStmt =
+ Actions.ActOnOpenMPCanonicalLoop(AssociatedStmt.get());
+ }
AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
} else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||
DKind == OMPD_target_exit_data) {
@@ -2550,6 +2585,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
}
case OMPD_declare_simd:
case OMPD_declare_target:
+ case OMPD_begin_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
case OMPD_begin_declare_variant:
@@ -2633,6 +2669,37 @@ bool Parser::ParseOpenMPSimpleVarList(
return !IsCorrect;
}
+OMPClause *Parser::ParseOpenMPSizesClause() {
+ SourceLocation ClauseNameLoc = ConsumeToken();
+ SmallVector<Expr *, 4> ValExprs;
+
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ return nullptr;
+ }
+
+ while (true) {
+ ExprResult Val = ParseConstantExpression();
+ if (!Val.isUsable()) {
+ T.skipToEnd();
+ return nullptr;
+ }
+
+ ValExprs.push_back(Val.get());
+
+ if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end))
+ break;
+
+ ExpectAndConsume(tok::comma);
+ }
+
+ T.consumeClose();
+
+ return Actions.ActOnOpenMPSizesClause(
+ ValExprs, ClauseNameLoc, T.getOpenLocation(), T.getCloseLocation());
+}
+
OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
SourceLocation Loc = Tok.getLocation();
ConsumeAnyToken();
@@ -2643,7 +2710,8 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
return nullptr;
SmallVector<Sema::UsesAllocatorsData, 4> Data;
do {
- ExprResult Allocator = ParseCXXIdExpression();
+ ExprResult Allocator =
+ getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression();
if (Allocator.isInvalid()) {
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
@@ -2655,7 +2723,8 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
BalancedDelimiterTracker T(*this, tok::l_paren,
tok::annot_pragma_openmp_end);
T.consumeOpen();
- ExprResult AllocatorTraits = ParseCXXIdExpression();
+ ExprResult AllocatorTraits =
+ getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression();
T.consumeClose();
if (AllocatorTraits.isInvalid()) {
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -2727,6 +2796,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_allocator:
case OMPC_depobj:
case OMPC_detach:
+ case OMPC_novariants:
+ case OMPC_nocontext:
+ case OMPC_filter:
+ case OMPC_partial:
// OpenMP [2.5, Restrictions]
// At most one num_threads clause can appear on the directive.
// OpenMP [2.8.1, simd construct, Restrictions]
@@ -2749,13 +2822,17 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
// At most one allocator clause can appear on the directive.
// OpenMP 5.0, 2.10.1 task Construct, Restrictions.
// At most one detach clause can appear on the directive.
+ // OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions.
+ // At most one novariants clause can appear on a dispatch directive.
+ // At most one nocontext clause can appear on a dispatch directive.
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
- if (CKind == OMPC_ordered && PP.LookAhead(/*N=*/0).isNot(tok::l_paren))
+ if ((CKind == OMPC_ordered || CKind == OMPC_partial) &&
+ PP.LookAhead(/*N=*/0).isNot(tok::l_paren))
Clause = ParseOpenMPClause(CKind, WrongDirective);
else
Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
@@ -2818,7 +2895,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
- case OMPC_destroy:
+ case OMPC_full:
// OpenMP [2.7.1, Restrictions, p. 9]
// Only one ordered clause can appear on a loop directive.
// OpenMP [2.7.1, Restrictions, C/C++, p. 4]
@@ -2870,9 +2947,33 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_affinity:
Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
break;
+ case OMPC_sizes:
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
+ ErrorFound = true;
+ }
+
+ Clause = ParseOpenMPSizesClause();
+ break;
case OMPC_uses_allocators:
Clause = ParseOpenMPUsesAllocatorClause(DKind);
break;
+ case OMPC_destroy:
+ if (DKind != OMPD_interop) {
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
+ ErrorFound = true;
+ }
+ Clause = ParseOpenMPClause(CKind, WrongDirective);
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ case OMPC_init:
+ case OMPC_use:
+ Clause = ParseOpenMPInteropClause(CKind, WrongDirective);
+ break;
case OMPC_device_type:
case OMPC_unknown:
skipUntilPragmaOpenMPEnd(DKind);
@@ -2969,6 +3070,144 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
}
+/// Parsing of OpenMP clauses that use an interop-var.
+///
+/// init-clause:
+/// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var)
+///
+/// destroy-clause:
+/// destroy(interop-var)
+///
+/// use-clause:
+/// use(interop-var)
+///
+/// interop-modifier:
+/// prefer_type(preference-list)
+///
+/// preference-list:
+/// foreign-runtime-id [, foreign-runtime-id]...
+///
+/// foreign-runtime-id:
+/// <string-literal> | <constant-integral-expression>
+///
+/// interop-type:
+/// target | targetsync
+///
+OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
+ bool ParseOnly) {
+ SourceLocation Loc = ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind).data()))
+ return nullptr;
+
+ bool IsTarget = false;
+ bool IsTargetSync = false;
+ SmallVector<Expr *, 4> Prefs;
+
+ if (Kind == OMPC_init) {
+
+ // Parse optional interop-modifier.
+ if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "prefer_type") {
+ ConsumeToken();
+ BalancedDelimiterTracker PT(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type"))
+ return nullptr;
+
+ while (Tok.isNot(tok::r_paren)) {
+ SourceLocation Loc = Tok.getLocation();
+ ExprResult LHS = ParseCastExpression(AnyCastExpr);
+ ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(
+ ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
+ /*DiscardedValue=*/false);
+ if (PTExpr.isUsable())
+ Prefs.push_back(PTExpr.get());
+ else
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ }
+ PT.consumeClose();
+ }
+
+ if (!Prefs.empty()) {
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ else
+ Diag(Tok, diag::err_omp_expected_punc_after_interop_mod);
+ }
+
+ // Parse the interop-types.
+ bool HasError = false;
+ while (Tok.is(tok::identifier)) {
+ if (PP.getSpelling(Tok) == "target") {
+ // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
+ // Each interop-type may be specified on an action-clause at most
+ // once.
+ if (IsTarget)
+ Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";
+ IsTarget = true;
+ } else if (PP.getSpelling(Tok) == "targetsync") {
+ if (IsTargetSync)
+ Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";
+ IsTargetSync = true;
+ } else {
+ HasError = true;
+ Diag(Tok, diag::err_omp_expected_interop_type);
+ }
+ ConsumeToken();
+
+ if (!Tok.is(tok::comma))
+ break;
+ ConsumeToken();
+ }
+ if (!HasError && !IsTarget && !IsTargetSync)
+ Diag(Tok, diag::err_omp_expected_interop_type);
+
+ if (Tok.is(tok::colon))
+ ConsumeToken();
+ else if (IsTarget || IsTargetSync)
+ Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";
+ }
+
+ // Parse the variable.
+ SourceLocation VarLoc = Tok.getLocation();
+ ExprResult InteropVarExpr =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
+ if (!InteropVarExpr.isUsable()) {
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+
+ // Parse ')'.
+ SourceLocation RLoc = Tok.getLocation();
+ if (!T.consumeClose())
+ RLoc = T.getCloseLocation();
+
+ if (ParseOnly || !InteropVarExpr.isUsable() ||
+ (Kind == OMPC_init && !IsTarget && !IsTargetSync))
+ return nullptr;
+
+ if (Kind == OMPC_init)
+ return Actions.ActOnOpenMPInitClause(InteropVarExpr.get(), Prefs, IsTarget,
+ IsTargetSync, Loc, T.getOpenLocation(),
+ VarLoc, RLoc);
+ if (Kind == OMPC_use)
+ return Actions.ActOnOpenMPUseClause(InteropVarExpr.get(), Loc,
+ T.getOpenLocation(), VarLoc, RLoc);
+
+ if (Kind == OMPC_destroy)
+ return Actions.ActOnOpenMPDestroyClause(InteropVarExpr.get(), Loc,
+ T.getOpenLocation(), VarLoc, RLoc);
+
+ llvm_unreachable("Unexpected interop variable clause.");
+}
+
/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
///
/// default-clause:
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index f9b852826775..42072fe63fc8 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -14,11 +14,13 @@
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Token.h"
#include "clang/Parse/LoopHint.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/Scope.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -292,6 +294,10 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler {
Token &FirstToken) override;
};
+void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
+ for (auto &T : Toks)
+ T.setFlag(clang::Token::IsReinjected);
+}
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -399,9 +405,11 @@ void Parser::initializePragmaHandlers() {
UnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("unroll");
PP.AddPragmaHandler(UnrollHintHandler.get());
+ PP.AddPragmaHandler("GCC", UnrollHintHandler.get());
NoUnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("nounroll");
PP.AddPragmaHandler(NoUnrollHintHandler.get());
+ PP.AddPragmaHandler("GCC", NoUnrollHintHandler.get());
UnrollAndJamHintHandler =
std::make_unique<PragmaUnrollHintHandler>("unroll_and_jam");
@@ -517,9 +525,11 @@ void Parser::resetPragmaHandlers() {
LoopHintHandler.reset();
PP.RemovePragmaHandler(UnrollHintHandler.get());
+ PP.RemovePragmaHandler("GCC", UnrollHintHandler.get());
UnrollHintHandler.reset();
PP.RemovePragmaHandler(NoUnrollHintHandler.get());
+ PP.RemovePragmaHandler("GCC", NoUnrollHintHandler.get());
NoUnrollHintHandler.reset();
PP.RemovePragmaHandler(UnrollAndJamHintHandler.get());
@@ -771,22 +781,21 @@ void Parser::HandlePragmaOpenCLExtension() {
// overriding all previously issued extension directives, but only if the
// behavior is set to disable."
if (Name == "all") {
- if (State == Disable) {
+ if (State == Disable)
Opt.disableAll();
- Opt.enableSupportedCore(getLangOpts());
- } else {
+ else
PP.Diag(NameLoc, diag::warn_pragma_expected_predicate) << 1;
- }
} else if (State == Begin) {
if (!Opt.isKnown(Name) || !Opt.isSupported(Name, getLangOpts())) {
Opt.support(Name);
+ // FIXME: Default behavior of the extension pragma is not defined.
+ // Therefore, it should never be added by default.
+ Opt.acceptsPragma(Name);
}
- Actions.setCurrentOpenCLExtension(Name);
} else if (State == End) {
- if (Name != Actions.getCurrentOpenCLExtension())
- PP.Diag(NameLoc, diag::warn_pragma_begin_end_mismatch);
- Actions.setCurrentOpenCLExtension("");
- } else if (!Opt.isKnown(Name))
+ // There is no behavior for this directive. We only accept this for
+ // backward compatibility.
+ } else if (!Opt.isKnown(Name) || !Opt.isWithPragma(Name))
PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident;
else if (Opt.isSupportedExtension(Name, getLangOpts()))
Opt.enable(Name, State == Enable);
@@ -2618,6 +2627,7 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP,
TokenVector.push_back(EoF);
// We must allocate this array with new because EnterTokenStream is going to
// delete it later.
+ markAsReinjectedForRelexing(TokenVector);
auto TokenArray = std::make_unique<Token[]>(TokenVector.size());
std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get());
auto Value = new (PP.getPreprocessorAllocator())
@@ -3175,6 +3185,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
EOFTok.setLocation(Tok.getLocation());
ValueList.push_back(EOFTok); // Terminates expression for parsing.
+ markAsReinjectedForRelexing(ValueList);
Info.Toks = llvm::makeArrayRef(ValueList).copy(PP.getPreprocessorAllocator());
Info.PragmaName = PragmaName;
@@ -3631,6 +3642,7 @@ void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
EOFTok.setLocation(EndLoc);
AttributeTokens.push_back(EOFTok);
+ markAsReinjectedForRelexing(AttributeTokens);
Info->Tokens =
llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
}
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 26a02575010c..ebfe048513b1 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -20,6 +20,8 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
+#include "llvm/ADT/STLExtras.h"
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -98,10 +100,15 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
ParenBraceBracketBalancer BalancerRAIIObj(*this);
+ // Because we're parsing either a statement or a declaration, the order of
+ // attribute parsing is important. [[]] attributes at the start of a
+ // statement are different from [[]] attributes that follow an __attribute__
+ // at the start of the statement. Thus, we're not using MaybeParseAttributes
+ // here because we don't want to allow arbitrary orderings.
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
- if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
- return StmtError();
+ if (getLangOpts().OpenCL)
+ MaybeParseGNUAttributes(Attrs);
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
Stmts, StmtCtx, TrailingElseLoc, Attrs);
@@ -113,7 +120,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
if (Attrs.empty() || Res.isInvalid())
return Res;
- return Actions.ProcessStmtAttributes(Res.get(), Attrs, Attrs.Range);
+ return Actions.ActOnAttributedStmt(Attrs, Res.get());
}
namespace {
@@ -165,14 +172,13 @@ Retry:
switch (Kind) {
case tok::at: // May be a @try or @throw statement
{
- ProhibitAttributes(Attrs); // TODO: is it correct?
AtLoc = ConsumeToken(); // consume @
return ParseObjCAtStatement(AtLoc, StmtCtx);
}
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
cutOffParsing();
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
return StmtError();
case tok::identifier: {
@@ -210,7 +216,11 @@ Retry:
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
ParsedStmtContext()) &&
- (GNUAttributeLoc.isValid() || isDeclarationStatement())) {
+ ((GNUAttributeLoc.isValid() &&
+ !(!Attrs.empty() &&
+ llvm::all_of(
+ Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) ||
+ isDeclarationStatement())) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl;
if (GNUAttributeLoc.isValid()) {
@@ -391,7 +401,12 @@ Retry:
return HandlePragmaCaptured();
case tok::annot_pragma_openmp:
+ // Prohibit attributes that are not OpenMP attributes, but only before
+ // processing a #pragma omp clause.
ProhibitAttributes(Attrs);
+ LLVM_FALLTHROUGH;
+ case tok::annot_attr_openmp:
+ // Do not prohibit attributes if they were OpenMP attributes.
return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
case tok::annot_pragma_ms_pointers_to_members:
@@ -638,19 +653,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs,
// attributes as part of a statement in that case). That looks like a bug.
if (!getLangOpts().CPlusPlus || Tok.is(tok::semi))
attrs.takeAllFrom(TempAttrs);
- else if (isDeclarationStatement()) {
+ else {
StmtVector Stmts;
- // FIXME: We should do this whether or not we have a declaration
- // statement, but that doesn't work correctly (because ProhibitAttributes
- // can't handle GNU attributes), so only call it in the one case where
- // GNU attributes are allowed.
SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx,
nullptr, TempAttrs);
if (!TempAttrs.empty() && !SubStmt.isInvalid())
- SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs,
- TempAttrs.Range);
- } else {
- Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi;
+ SubStmt = Actions.ActOnAttributedStmt(TempAttrs, SubStmt.get());
}
}
@@ -715,8 +723,8 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
ColonLoc = SourceLocation();
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteCase(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteCase(getCurScope());
return StmtError();
}
@@ -1134,7 +1142,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
R = handleExprStmt(Res, SubStmtCtx);
if (R.isUsable())
- R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range);
+ R = Actions.ActOnAttributedStmt(attrs, R.get());
}
}
@@ -1461,8 +1469,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// Pop the 'else' scope if needed.
InnerScope.Exit();
} else if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen);
cutOffParsing();
+ Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen);
return StmtError();
} else if (InnerStatementTrailingElseLoc.isValid()) {
Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
@@ -1816,10 +1824,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
FullExprArg ThirdPart(Actions);
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
C99orCXXorObjC? Sema::PCC_ForInit
: Sema::PCC_Expression);
- cutOffParsing();
return StmtError();
}
@@ -1887,8 +1895,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
cutOffParsing();
+ Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
return StmtError();
}
Collection = ParseExpression();
@@ -1923,8 +1931,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
cutOffParsing();
+ Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
return StmtError();
}
Collection = ParseExpression();
@@ -1948,7 +1956,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
// Parse the second part of the for specifier.
- getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() &&
!SecondPart.isInvalid()) {
// Parse the second part of the for specifier.
@@ -1964,7 +1971,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SecondPart =
ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean,
- MightBeForRangeStmt ? &ForRangeInfo : nullptr);
+ MightBeForRangeStmt ? &ForRangeInfo : nullptr,
+ /*EnterForConditionScope*/ true);
if (ForRangeInfo.ParsedForRangeDecl()) {
Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc()
@@ -1981,6 +1989,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
}
} else {
+ // We permit 'continue' and 'break' in the condition of a for loop.
+ getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
+
ExprResult SecondExpr = ParseExpression();
if (SecondExpr.isInvalid())
SecondPart = Sema::ConditionError();
@@ -1992,6 +2003,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
}
+ // Enter a break / continue scope, if we didn't already enter one while
+ // parsing the second part.
+ if (!(getCurScope()->getFlags() & Scope::ContinueScope))
+ getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
+
// Parse the third part of the for statement.
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
if (Tok.isNot(tok::semi)) {
@@ -2177,9 +2193,9 @@ StmtResult Parser::ParseReturnStatement() {
PreferredType.enterReturn(Actions, Tok.getLocation());
// FIXME: Code completion for co_return.
if (Tok.is(tok::code_completion) && !IsCoreturn) {
+ cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
- cutOffParsing();
return StmtError();
}
@@ -2548,19 +2564,3 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
}
Braces.consumeClose();
}
-
-bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
- MaybeParseGNUAttributes(Attrs);
-
- if (Attrs.empty())
- return true;
-
- if (Attrs.begin()->getKind() != ParsedAttr::AT_OpenCLUnrollHint)
- return true;
-
- if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
- Diag(Tok, diag::err_opencl_unroll_hint_on_non_loop);
- return false;
- }
- return true;
-}
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp
index bdf40c291cb6..e520151dcad7 100644
--- a/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/clang/lib/Parse/ParseStmtAsm.cpp
@@ -577,19 +577,22 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
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) {
+
+ if (!MAI || !MII || !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);
- MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx);
+ llvm::MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &TempSrcMgr);
+ std::unique_ptr<llvm::MCObjectFileInfo> MOFI(
+ TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
+ Ctx.setObjectFileInfo(MOFI.get());
+
std::unique_ptr<llvm::MemoryBuffer> Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
@@ -630,9 +633,9 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
SmallVector<std::pair<void *, bool>, 4> OpExprs;
SmallVector<std::string, 4> Constraints;
SmallVector<std::string, 4> Clobbers;
- if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,
- NumInputs, OpExprs, Constraints, Clobbers,
- MII.get(), IP.get(), Callback))
+ if (Parser->parseMSInlineAsm(AsmStringIR, NumOutputs, NumInputs, OpExprs,
+ Constraints, Clobbers, MII.get(), IP.get(),
+ Callback))
return StmtError();
// Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 3bf2bc455bfe..c0bfbbde40ac 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -353,8 +353,8 @@ struct Parser::ConditionDeclarationOrInitStatementState {
if (CanBeForRangeDecl) {
// Skip until we hit a ')', ';', or a ':' with no matching '?'.
// The final case is a for range declaration, the rest are not.
+ unsigned QuestionColonDepth = 0;
while (true) {
- unsigned QuestionColonDepth = 0;
P.SkipUntil({tok::r_paren, tok::semi, tok::question, tok::colon},
StopBeforeMatch);
if (P.Tok.is(tok::question))
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 9b0f921b4269..c81dd03ffaaa 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -49,10 +49,10 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
}
Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
- : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
- GreaterThanIsOperator(true), ColonIsSacred(false),
- InMessageExpression(false), TemplateParameterDepth(0),
- ParsingInObjCContainer(false) {
+ : PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions),
+ Diags(PP.getDiagnostics()), GreaterThanIsOperator(true),
+ ColonIsSacred(false), InMessageExpression(false),
+ TemplateParameterDepth(0), ParsingInObjCContainer(false) {
SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
Tok.startToken();
Tok.setKind(tok::eof);
@@ -309,6 +309,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
return false;
case tok::annot_pragma_openmp:
+ case tok::annot_attr_openmp:
case tok::annot_pragma_openmp_end:
// Stop before an OpenMP pragma boundary.
if (OpenMPDirectiveParsing)
@@ -494,6 +495,7 @@ void Parser::Initialize() {
Ident_instancetype = nullptr;
Ident_final = nullptr;
Ident_sealed = nullptr;
+ Ident_abstract = nullptr;
Ident_override = nullptr;
Ident_GNU_final = nullptr;
Ident_import = nullptr;
@@ -503,10 +505,12 @@ void Parser::Initialize() {
Ident_vector = nullptr;
Ident_bool = nullptr;
+ Ident_Bool = nullptr;
Ident_pixel = nullptr;
if (getLangOpts().AltiVec || getLangOpts().ZVector) {
Ident_vector = &PP.getIdentifierTable().get("vector");
Ident_bool = &PP.getIdentifierTable().get("bool");
+ Ident_Bool = &PP.getIdentifierTable().get("_Bool");
}
if (getLangOpts().AltiVec)
Ident_pixel = &PP.getIdentifierTable().get("pixel");
@@ -795,6 +799,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return nullptr;
+ case tok::annot_attr_openmp:
case tok::annot_pragma_openmp: {
AccessSpecifier AS = AS_none;
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
@@ -870,6 +875,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SingleDecl = ParseObjCMethodDefinition();
break;
case tok::code_completion:
+ cutOffParsing();
if (CurParsedObjCImpl) {
// Code-complete Objective-C methods even without leading '-'/'+' prefix.
Actions.CodeCompleteObjCMethodDecl(getCurScope(),
@@ -879,7 +885,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Actions.CodeCompleteOrdinaryName(
getCurScope(),
CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace);
- cutOffParsing();
return nullptr;
case tok::kw_import:
SingleDecl = ParseModuleImport(SourceLocation());
@@ -1079,8 +1084,6 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
DS, AnonRecord);
DS.complete(TheDecl);
- if (getLangOpts().OpenCL)
- Actions.setCurrentOpenCLExtensionForDecl(TheDecl);
if (AnonRecord) {
Decl* decls[] = {AnonRecord, TheDecl};
return Actions.BuildDeclaratorGroup(decls);
@@ -1213,7 +1216,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// a definition. Late parsed attributes are checked at the end.
if (Tok.isNot(tok::equal)) {
for (const ParsedAttr &AL : D.getAttributes())
- if (AL.isKnownToGCC() && !AL.isCXX11Attribute())
+ if (AL.isKnownToGCC() && !AL.isStandardAttributeSyntax())
Diag(AL.getLoc(), diag::warn_attribute_on_function_definition) << AL;
}
@@ -1695,6 +1698,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
break;
case Sema::NC_Type: {
+ if (TryAltiVecVectorToken())
+ // vector has been found as a type id when altivec is enabled but
+ // this is followed by a declaration specifier so this is really the
+ // altivec vector token. Leave it unannotated.
+ break;
SourceLocation BeginLoc = NameLoc;
if (SS.isNotEmpty())
BeginLoc = SS.getBeginLoc();
@@ -1736,6 +1744,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
return ANK_Success;
case Sema::NC_NonType:
+ if (TryAltiVecVectorToken())
+ // vector has been found as a non-type id when altivec is enabled but
+ // this is followed by a declaration specifier so this is really the
+ // altivec vector token. Leave it unannotated.
+ break;
Tok.setKind(tok::annot_non_type);
setNonTypeAnnotation(Tok, Classification.getNonTypeDecl());
Tok.setLocation(NameLoc);
@@ -2114,21 +2127,21 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
for (Scope *S = getCurScope(); S; S = S->getParent()) {
if (S->getFlags() & Scope::FnScope) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
Sema::PCC_RecoveryInFunction);
- cutOffParsing();
return PrevTokLocation;
}
if (S->getFlags() & Scope::ClassScope) {
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
cutOffParsing();
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
return PrevTokLocation;
}
}
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
cutOffParsing();
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
return PrevTokLocation;
}
@@ -2452,8 +2465,8 @@ bool Parser::ParseModuleName(
while (true) {
if (!Tok.is(tok::identifier)) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteModuleImport(UseLoc, Path);
cutOffParsing();
+ Actions.CodeCompleteModuleImport(UseLoc, Path);
return true;
}