summaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r--lib/Parse/ParseDecl.cpp258
1 files changed, 196 insertions, 62 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 298a2bad56c60..73b4f50fda460 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1,9 +1,8 @@
//===--- ParseDecl.cpp - Declaration Parsing --------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -86,6 +85,23 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
#undef CLANG_ATTR_LATE_PARSED_LIST
}
+/// Check if the a start and end source location expand to the same macro.
+bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!StartLoc.isMacroID() || !EndLoc.isMacroID())
+ return false;
+
+ SourceManager &SM = PP.getSourceManager();
+ if (SM.getFileID(StartLoc) != SM.getFileID(EndLoc))
+ return false;
+
+ bool AttrStartIsInMacro =
+ Lexer::isAtStartOfMacroExpansion(StartLoc, SM, PP.getLangOpts());
+ bool AttrEndIsInMacro =
+ Lexer::isAtEndOfMacroExpansion(EndLoc, SM, PP.getLangOpts());
+ return AttrStartIsInMacro && AttrEndIsInMacro;
+}
+
/// ParseGNUAttributes - Parse a non-empty attributes list.
///
/// [GNU] attributes:
@@ -134,7 +150,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
while (Tok.is(tok::kw___attribute)) {
- ConsumeToken();
+ SourceLocation AttrTokLoc = ConsumeToken();
+ unsigned OldNumAttrs = attrs.size();
+ unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0;
+
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
"attribute")) {
SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ;
@@ -145,10 +164,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
return;
}
// Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
- while (true) {
- // Allow empty/non-empty attributes. ((__vector_size__(16),,,,))
- if (TryConsumeToken(tok::comma))
- continue;
+ do {
+ // Eat preceeding commas to allow __attribute__((,,,foo))
+ while (TryConsumeToken(tok::comma))
+ ;
// Expect an identifier or declaration specifier (const, int, etc.)
if (Tok.isAnnotation())
@@ -193,7 +212,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
Eof.startToken();
Eof.setLocation(Tok.getLocation());
LA->Toks.push_back(Eof);
- }
+ } while (Tok.is(tok::comma));
if (ExpectAndConsume(tok::r_paren))
SkipUntil(tok::r_paren, StopAtSemi);
@@ -202,6 +221,25 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SkipUntil(tok::r_paren, StopAtSemi);
if (endLoc)
*endLoc = Loc;
+
+ // If this was declared in a macro, attach the macro IdentifierInfo to the
+ // parsed attribute.
+ auto &SM = PP.getSourceManager();
+ if (!SM.isWrittenInBuiltinFile(SM.getSpellingLoc(AttrTokLoc)) &&
+ FindLocsWithCommonFileID(PP, AttrTokLoc, Loc)) {
+ CharSourceRange ExpansionRange = SM.getExpansionRange(AttrTokLoc);
+ StringRef FoundName =
+ 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());
+
+ if (LateAttrs) {
+ for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i)
+ (*LateAttrs)[i]->MacroII = MacroII;
+ }
+ }
}
}
@@ -223,6 +261,15 @@ static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) {
#undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
}
+/// Determine whether the given attribute treats kw_this as an identifier.
+static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II) {
+#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+ .Default(false);
+#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
+}
+
/// Determine whether the given attribute parses a type argument.
static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
#define CLANG_ATTR_TYPE_ARG_LIST
@@ -287,6 +334,12 @@ unsigned Parser::ParseAttributeArgsCommon(
// Ignore the left paren location for now.
ConsumeParen();
+ bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName);
+
+ // Interpret "kw_this" as an identifier if the attributed requests it.
+ if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
+ Tok.setKind(tok::identifier);
+
ArgsVector ArgExprs;
if (Tok.is(tok::identifier)) {
// If this attribute wants an 'identifier' argument, make it so.
@@ -314,6 +367,10 @@ unsigned Parser::ParseAttributeArgsCommon(
// Parse the non-empty comma-separated list of expressions.
do {
+ // Interpret "kw_this" as an identifier if the attributed requests it.
+ if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
+ Tok.setKind(tok::identifier);
+
ExprResult ArgExpr;
if (Tok.is(tok::identifier) &&
attributeHasVariadicIdentifierArg(*AttrName)) {
@@ -1413,7 +1470,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
LA.Toks.push_back(Tok);
- PP.EnterTokenStream(LA.Toks, true);
+ PP.EnterTokenStream(LA.Toks, true, /*IsReinject=*/true);
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
@@ -1716,7 +1773,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
/// [C++11] attribute-specifier-seq decl-specifier-seq[opt]
/// init-declarator-list ';'
///[C90/C++]init-declarator-list ';' [TODO]
-/// [OMP] threadprivate-directive [TODO]
+/// [OMP] threadprivate-directive
+/// [OMP] allocate-directive [TODO]
///
/// for-range-declaration: [C++11 6.5p1: stmt.ranged]
/// attribute-specifier-seq[opt] type-specifier-seq declarator
@@ -2275,7 +2333,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
return nullptr;
}
- ExprResult Init(ParseInitializer());
+ PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
+ ExprResult Init = ParseInitializer();
// If this is the only decl in (possibly) range based for statement,
// our best guess is that the user meant ':' instead of '='.
@@ -2313,25 +2372,27 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
InitializerScopeRAII InitScope(*this, D, ThisDecl);
- llvm::function_ref<void()> ExprListCompleter;
auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
- auto ConstructorCompleter = [&, ThisVarDecl] {
+ auto RunSignatureHelp = [&]() {
QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
ThisDecl->getLocation(), Exprs, T.getOpenLocation());
CalledSignatureHelp = true;
- Actions.CodeCompleteExpression(getCurScope(), PreferredType);
+ return PreferredType;
+ };
+ auto SetPreferredType = [&] {
+ PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp);
};
+
+ llvm::function_ref<void()> ExpressionStarts;
if (ThisVarDecl) {
// ParseExpressionList can sometimes succeed even when ThisDecl is not
// VarDecl. This is an error and it is reported in a call to
// Actions.ActOnInitializerError(). However, we call
- // ProduceConstructorSignatureHelp only on VarDecls, falling back to
- // default completer in other cases.
- ExprListCompleter = ConstructorCompleter;
+ // ProduceConstructorSignatureHelp only on VarDecls.
+ ExpressionStarts = SetPreferredType;
}
-
- if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) {
+ if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
@@ -2420,14 +2481,15 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
if (DS.isVirtualSpecified())
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
- if (DS.isExplicitSpecified())
+ if (DS.hasExplicitSpecifier())
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
DS.ClearFunctionSpecs();
}
- // Issue diagnostic and remove constexpr specfier if present.
- if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
- Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
+ // Issue diagnostic and remove constexpr specifier if present.
+ if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) {
+ Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr)
+ << (DS.getConstexprSpecifier() == CSK_consteval);
DS.ClearConstexprSpec();
}
}
@@ -2499,6 +2561,11 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
return false;
}
+ // Early exit as Sema has a dedicated missing_actual_pipe_type diagnostic
+ // for incomplete declarations such as `pipe p`.
+ if (getLangOpts().OpenCLCPlusPlus && DS.isTypeSpecPipe())
+ return false;
+
if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
// Don't require a type specifier if we have the 'auto' storage class
@@ -2627,6 +2694,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
case tok::semi:
// This looks like a variable or function declaration. The type is
// probably missing. We're done parsing decl-specifiers.
+ // But only if we are not in a function prototype scope.
+ if (getCurScope()->isFunctionPrototypeScope())
+ break;
if (SS)
AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
return false;
@@ -2680,7 +2750,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// TODO: Could inject an invalid typedef decl in an enclosing scope to
// avoid rippling error messages on subsequent uses of the same type,
// could be useful if #include was forgotten.
- return false;
+ return true;
}
/// Determine the declaration specifier context from the declarator
@@ -2832,7 +2902,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
IdentifierInfo *Name = AfterScope.getIdentifierInfo();
Sema::NameClassification Classification = Actions.ClassifyName(
getCurScope(), SS, Name, AfterScope.getLocation(), Next,
- /*IsAddressOfOperand*/false);
+ /*IsAddressOfOperand=*/false, /*CCC=*/nullptr);
switch (Classification.getKind()) {
case Sema::NC_Error:
SkipMalformedDecl();
@@ -2853,6 +2923,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
case Sema::NC_Expression:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
+ case Sema::NC_UndeclaredTemplate:
// Might be a redeclaration of a prior entity.
break;
}
@@ -2943,6 +3014,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
+ // This value needs to be set to the location of the last token if the last
+ // token of the specifier is already consumed.
+ SourceLocation ConsumedEnd;
+
// HACK: MSVC doesn't consider _Atomic to be a keyword and its STL
// implementation for VS2013 uses _Atomic as an identifier for one of the
// classes in <atomic>.
@@ -3114,7 +3189,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
getCurScope(), &SS, false, false, nullptr,
/*IsCtorOrDtorName=*/false,
- /*WantNonTrivialSourceInfo=*/true,
+ /*WantNontrivialTypeSourceInfo=*/true,
isClassTemplateDeductionContext(DSContext));
// If the referenced identifier is not a type, then this declspec is
@@ -3323,7 +3398,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// type-name
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- if (TemplateId->Kind != TNK_Type_template) {
+ if (TemplateId->Kind != TNK_Type_template &&
+ TemplateId->Kind != TNK_Undeclared_template) {
// This template-id does not refer to a type name, so we're
// done with the type-specifiers.
goto DoneWithDeclSpec;
@@ -3483,7 +3559,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID);
break;
case tok::kw_virtual:
- // OpenCL C++ v1.0 s2.9: the virtual function qualifier is not supported.
+ // C++ for OpenCL does not allow virtual function qualifier, to avoid
+ // function pointers restricted in OpenCL v2.0 s6.9.a.
if (getLangOpts().OpenCLCPlusPlus) {
DiagID = diag::err_openclcxx_virtual_function;
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
@@ -3493,9 +3570,33 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
}
break;
- case tok::kw_explicit:
- isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID);
+ case tok::kw_explicit: {
+ SourceLocation ExplicitLoc = Loc;
+ SourceLocation CloseParenLoc;
+ ExplicitSpecifier ExplicitSpec(nullptr, ExplicitSpecKind::ResolvedTrue);
+ ConsumedEnd = ExplicitLoc;
+ ConsumeToken(); // kw_explicit
+ if (Tok.is(tok::l_paren)) {
+ if (getLangOpts().CPlusPlus2a) {
+ ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
+ BalancedDelimiterTracker Tracker(*this, tok::l_paren);
+ Tracker.consumeOpen();
+ ExplicitExpr = ParseConstantExpression();
+ ConsumedEnd = Tok.getLocation();
+ if (ExplicitExpr.isUsable()) {
+ CloseParenLoc = Tok.getLocation();
+ Tracker.consumeClose();
+ ExplicitSpec =
+ Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
+ } else
+ Tracker.skipToEnd();
+ } else
+ Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
+ }
+ isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
+ ExplicitSpec, CloseParenLoc);
break;
+ }
case tok::kw__Noreturn:
if (!getLangOpts().C11)
Diag(Loc, diag::ext_c11_noreturn);
@@ -3527,7 +3628,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// constexpr
case tok::kw_constexpr:
- isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID);
+ break;
+
+ // consteval
+ case tok::kw_consteval:
+ isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID);
break;
// type-specifier
@@ -3675,7 +3781,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_pipe:
- if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200)) {
+ 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.
Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
@@ -3790,19 +3897,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
getLangOpts());
break;
- // OpenCL access qualifiers:
- case tok::kw___read_only:
- case tok::kw___write_only:
- case tok::kw___read_write:
- // OpenCL C++ 1.0 s2.2: access qualifiers are reserved keywords.
- if (Actions.getLangOpts().OpenCLCPlusPlus) {
- DiagID = diag::err_openclcxx_reserved;
- PrevSpec = Tok.getIdentifierInfo()->getNameStart();
- isInvalid = true;
- }
- ParseOpenCLQualifiers(DS.getAttributes());
- break;
-
// OpenCL address space qualifiers:
case tok::kw___generic:
// generic address space is introduced only in OpenCL v2.0
@@ -3815,10 +3909,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
};
LLVM_FALLTHROUGH;
+ case tok::kw_private:
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
case tok::kw___constant:
+ // OpenCL access qualifiers:
+ case tok::kw___read_only:
+ case tok::kw___write_only:
+ case tok::kw___read_write:
ParseOpenCLQualifiers(DS.getAttributes());
break;
@@ -3847,25 +3946,29 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If a type specifier follows, it will be diagnosed elsewhere.
continue;
}
+
+ DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation());
+
// If the specifier wasn't legal, issue a diagnostic.
if (isInvalid) {
assert(PrevSpec && "Method did not return previous specifier!");
assert(DiagID);
if (DiagID == diag::ext_duplicate_declspec ||
- DiagID == diag::ext_warn_duplicate_declspec)
- Diag(Tok, DiagID)
- << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
+ DiagID == diag::ext_warn_duplicate_declspec ||
+ DiagID == diag::err_duplicate_declspec)
+ Diag(Loc, DiagID) << PrevSpec
+ << FixItHint::CreateRemoval(
+ SourceRange(Loc, DS.getEndLoc()));
else if (DiagID == diag::err_opencl_unknown_type_specifier) {
- Diag(Tok, DiagID) << getLangOpts().OpenCLCPlusPlus
- << getLangOpts().getOpenCLVersionTuple().getAsString()
- << PrevSpec << isStorageClass;
+ Diag(Loc, DiagID) << getLangOpts().OpenCLCPlusPlus
+ << getLangOpts().getOpenCLVersionTuple().getAsString()
+ << PrevSpec << isStorageClass;
} else
- Diag(Tok, DiagID) << PrevSpec;
+ Diag(Loc, DiagID) << PrevSpec;
}
- DS.SetRangeEnd(Tok.getLocation());
- if (DiagID != diag::err_bool_redeclaration)
+ if (DiagID != diag::err_bool_redeclaration && ConsumedEnd.isInvalid())
// After an error the next token can be an annotation token.
ConsumeAnyToken();
@@ -3876,6 +3979,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// ParseStructDeclaration - Parse a struct declaration without the terminating
/// semicolon.
///
+/// Note that a struct declaration refers to a declaration in a struct,
+/// not to the declaration of a struct.
+///
/// struct-declaration:
/// [C2x] attributes-specifier-seq[opt]
/// specifier-qualifier-list struct-declarator-list
@@ -4331,7 +4437,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.isNot(tok::semi)) {
// A semicolon was missing after this declaration. Diagnose and recover.
ExpectAndConsume(tok::semi, diag::err_expected_after, "enum");
- PP.EnterToken(Tok);
+ PP.EnterToken(Tok, /*IsReinject=*/true);
Tok.setKind(tok::semi);
}
} else {
@@ -4609,7 +4715,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// Push this token back into the preprocessor and change our current token
// to ';' so that the rest of the code recovers as though there were an
// ';' after the definition.
- PP.EnterToken(Tok);
+ PP.EnterToken(Tok, /*IsReinject=*/true);
Tok.setKind(tok::semi);
}
}
@@ -4782,9 +4888,11 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
-
return true;
+ case tok::kw_private:
+ return getLangOpts().OpenCL;
+
// C11 _Atomic
case tok::kw__Atomic:
return true;
@@ -4801,7 +4909,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
default: return false;
case tok::kw_pipe:
- return getLangOpts().OpenCL && (getLangOpts().OpenCLVersion >= 200);
+ return (getLangOpts().OpenCL && getLangOpts().OpenCLVersion >= 200) ||
+ getLangOpts().OpenCLCPlusPlus;
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
@@ -4929,6 +5038,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::annot_decltype:
case tok::kw_constexpr:
+ // C++20 consteval.
+ case tok::kw_consteval:
+
// C11 _Atomic
case tok::kw__Atomic:
return true;
@@ -4976,6 +5088,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
#include "clang/Basic/OpenCLImageTypes.def"
return true;
+
+ case tok::kw_private:
+ return getLangOpts().OpenCL;
}
}
@@ -5176,6 +5291,10 @@ void Parser::ParseTypeQualifierListOpt(
break;
// OpenCL qualifiers:
+ case tok::kw_private:
+ if (!getLangOpts().OpenCL)
+ goto DoneWithTypeQuals;
+ LLVM_FALLTHROUGH;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -5282,7 +5401,8 @@ 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))
+ if (Kind == tok::kw_pipe &&
+ ((Lang.OpenCL && Lang.OpenCLVersion >= 200) || Lang.OpenCLCPlusPlus))
return true;
if (!Lang.CPlusPlus)
@@ -6157,8 +6277,22 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
Actions.CurContext->isRecord());
Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers());
- if (D.getDeclSpec().isConstexprSpecified() && !getLangOpts().CPlusPlus14)
+ if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14)
Q.addConst();
+ // FIXME: Collect C++ address spaces.
+ // If there are multiple different address spaces, the source is invalid.
+ // Carry on using the first addr space for the qualifiers of 'this'.
+ // The diagnostic will be given later while creating the function
+ // prototype for the method.
+ if (getLangOpts().OpenCLCPlusPlus) {
+ for (ParsedAttr &attr : DS.getAttributes()) {
+ LangAS ASIdx = attr.asOpenCLLangAS();
+ if (ASIdx != LangAS::Default) {
+ Q.addAddressSpace(ASIdx);
+ break;
+ }
+ }
+ }
Sema::CXXThisScopeRAII ThisScope(
Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q,