#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#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"
#include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h"
#include <numeric>
using namespace clang;
static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
switch (Kind) {
case tok::unknown: return 0;
case tok::kw_addrspace_cast: return 1;
case tok::kw_const_cast: return 2;
case tok::kw_dynamic_cast: return 3;
case tok::kw_reinterpret_cast: return 4;
case tok::kw_static_cast: return 5;
default:
llvm_unreachable("Unknown type for digraph error message.");
}
}
bool Parser::areTokensAdjacent(const Token &First, const Token &Second) {
SourceManager &SM = PP.getSourceManager();
SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation());
SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength());
return FirstEnd == SM.getSpellingLoc(Second.getLocation());
}
static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken,
Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) {
if (!AtDigraph)
PP.Lex(DigraphToken);
PP.Lex(ColonToken);
SourceRange Range;
Range.setBegin(DigraphToken.getLocation());
Range.setEnd(ColonToken.getLocation());
P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph)
<< SelectDigraphErrorMessage(Kind)
<< FixItHint::CreateReplacement(Range, "< ::");
ColonToken.setKind(tok::coloncolon);
ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1));
ColonToken.setLength(2);
DigraphToken.setKind(tok::less);
DigraphToken.setLength(1);
PP.EnterToken(ColonToken, true);
if (!AtDigraph)
PP.EnterToken(DigraphToken, true);
}
void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
bool EnteringContext,
IdentifierInfo &II, CXXScopeSpec &SS) {
if (!Next.is(tok::l_square) || Next.getLength() != 2)
return;
Token SecondToken = GetLookAheadToken(2);
if (!SecondToken.is(tok::colon) || !areTokensAdjacent(Next, SecondToken))
return;
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&II, Tok.getLocation());
bool MemberOfUnknownSpecialization;
if (!Actions.isTemplateName(getCurScope(), SS, false,
TemplateName, ObjectType, EnteringContext,
Template, MemberOfUnknownSpecialization))
return;
FixDigraph(*this, PP, Next, SecondToken, tok::unknown,
false);
}
bool Parser::ParseOptionalCXXScopeSpecifier(
CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename,
IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
if (Tok.is(tok::annot_cxxscope)) {
assert(!LastII && "want last identifier but have already annotated scope");
assert(!MayBePseudoDestructor && "unexpected annot_cxxscope");
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
ConsumeAnnotationToken();
return false;
}
bool CheckForDestructor = false;
if (MayBePseudoDestructor && *MayBePseudoDestructor) {
CheckForDestructor = true;
*MayBePseudoDestructor = false;
}
if (LastII)
*LastII = nullptr;
bool HasScopeSpecifier = false;
if (Tok.is(tok::coloncolon)) {
tok::TokenKind NextKind = NextToken().getKind();
if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
return false;
if (NextKind == tok::l_brace) {
Diag(ConsumeToken(), diag::err_expected) << tok::identifier;
} else {
if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS))
return true;
HasScopeSpecifier = true;
}
}
if (Tok.is(tok::kw___super)) {
SourceLocation SuperLoc = ConsumeToken();
if (!Tok.is(tok::coloncolon)) {
Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super);
return true;
}
return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS);
}
if (!HasScopeSpecifier &&
Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) {
DeclSpec DS(AttrFactory);
SourceLocation DeclLoc = Tok.getLocation();
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
SourceLocation CCLoc;
if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto ||
!TryConsumeToken(tok::coloncolon, CCLoc)) {
AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc);
return false;
}
if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc))
SS.SetInvalid(SourceRange(DeclLoc, CCLoc));
HasScopeSpecifier = true;
}
auto SavedType = PreferredType;
while (true) {
if (HasScopeSpecifier) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext,
InUsingDeclaration, ObjectType.get(),
SavedType.get(SS.getBeginLoc()));
SS.setEndLoc(Tok.getLocation());
return true;
}
ObjectType = nullptr;
}
if (Tok.is(tok::kw_template)) {
if (!HasScopeSpecifier && !ObjectType)
break;
TentativeParsingAction TPA(*this);
SourceLocation TemplateKWLoc = ConsumeToken();
UnqualifiedId TemplateName;
if (Tok.is(tok::identifier)) {
TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
} else if (Tok.is(tok::kw_operator)) {
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
TemplateName)) {
TPA.Commit();
break;
}
if (TemplateName.getKind() != UnqualifiedIdKind::IK_OperatorFunctionId &&
TemplateName.getKind() != UnqualifiedIdKind::IK_LiteralOperatorId) {
Diag(TemplateName.getSourceRange().getBegin(),
diag::err_id_after_template_in_nested_name_spec)
<< TemplateName.getSourceRange();
TPA.Commit();
break;
}
} else {
TPA.Revert();
break;
}
if (Tok.isNot(tok::less)) {
TPA.Revert();
break;
}
TPA.Commit();
TemplateTy Template;
TemplateNameKind TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
EnteringContext, Template, true);
if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc,
TemplateName, false))
return true;
continue;
}
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
*MayBePseudoDestructor = true;
return false;
}
if (LastII)
*LastII = TemplateId->Name;
ConsumeAnnotationToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
HasScopeSpecifier = true;
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (TemplateId->isInvalid() ||
Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
CCLoc,
EnteringContext)) {
SourceLocation StartLoc
= SS.getBeginLoc().isValid()? SS.getBeginLoc()
: TemplateId->TemplateNameLoc;
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
continue;
}
if (Tok.isNot(tok::identifier))
break;
IdentifierInfo &II = *Tok.getIdentifierInfo();
Token Next = NextToken();
Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(),
ObjectType);
if (Next.is(tok::colon) && !ColonIsSacred) {
if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, IdInfo,
EnteringContext) &&
PP.LookAhead(1).is(tok::identifier)) {
Diag(Next, diag::err_unexpected_colon_in_nested_name_spec)
<< FixItHint::CreateReplacement(Next.getLocation(), "::");
Next.setKind(tok::coloncolon);
}
}
if (Next.is(tok::coloncolon) && GetLookAheadToken(2).is(tok::l_brace)) {
Token Identifier = Tok; ConsumeToken(); Diag(PP.getLocForEndOfToken(ConsumeToken()), diag::err_expected)
<< tok::identifier;
UnconsumeToken(Identifier); Next = NextToken(); }
if (Next.is(tok::coloncolon)) {
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
*MayBePseudoDestructor = true;
return false;
}
if (ColonIsSacred) {
const Token &Next2 = GetLookAheadToken(2);
if (Next2.is(tok::kw_private) || Next2.is(tok::kw_protected) ||
Next2.is(tok::kw_public) || Next2.is(tok::kw_virtual)) {
Diag(Next2, diag::err_unexpected_token_in_nested_name_spec)
<< Next2.getName()
<< FixItHint::CreateReplacement(Next.getLocation(), ":");
Token ColonColon;
PP.Lex(ColonColon);
ColonColon.setKind(tok::colon);
PP.EnterToken(ColonColon, true);
break;
}
}
if (LastII)
*LastII = &II;
Token Identifier = Tok;
SourceLocation IdLoc = ConsumeToken();
assert(Tok.isOneOf(tok::coloncolon, tok::colon) &&
"NextToken() not working properly!");
Token ColonColon = Tok;
SourceLocation CCLoc = ConsumeToken();
bool IsCorrectedToColon = false;
bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
if (Actions.ActOnCXXNestedNameSpecifier(
getCurScope(), IdInfo, EnteringContext, SS, CorrectionFlagPtr,
OnlyNamespace)) {
if (CorrectionFlagPtr && IsCorrectedToColon) {
ColonColon.setKind(tok::colon);
PP.EnterToken(Tok, true);
PP.EnterToken(ColonColon, true);
Tok = Identifier;
break;
}
SS.SetInvalid(SourceRange(IdLoc, CCLoc));
}
HasScopeSpecifier = true;
continue;
}
CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS);
if (Next.is(tok::less)) {
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&II, Tok.getLocation());
bool MemberOfUnknownSpecialization;
if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS,
false,
TemplateName,
ObjectType,
EnteringContext,
Template,
MemberOfUnknownSpecialization)) {
if (!IsTypename && TNK == TNK_Undeclared_template &&
isTemplateArgumentList(1) == TPResult::False)
break;
ConsumeToken();
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
TemplateName, false))
return true;
continue;
}
if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
(IsTypename || isTemplateArgumentList(1) == TPResult::True)) {
if (!ObjectHadErrors) {
unsigned DiagID = diag::err_missing_dependent_template_keyword;
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_missing_dependent_template_keyword;
Diag(Tok.getLocation(), DiagID)
<< II.getName()
<< FixItHint::CreateInsertion(Tok.getLocation(), "template ");
}
SourceLocation TemplateNameLoc = ConsumeToken();
TemplateNameKind TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateNameLoc, TemplateName, ObjectType,
EnteringContext, Template, true);
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
TemplateName, false))
return true;
continue;
}
}
break;
}
if (CheckForDestructor && !HasScopeSpecifier && Tok.is(tok::tilde))
*MayBePseudoDestructor = true;
return false;
}
ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
bool isAddressOfOperand,
Token &Replacement) {
ExprResult E;
switch (Tok.getKind()) {
case tok::annot_non_type: {
NamedDecl *ND = getNonTypeAnnotation(Tok);
SourceLocation Loc = ConsumeAnnotationToken();
E = Actions.ActOnNameClassifiedAsNonType(getCurScope(), SS, ND, Loc, Tok);
break;
}
case tok::annot_non_type_dependent: {
IdentifierInfo *II = getIdentifierAnnotation(Tok);
SourceLocation Loc = ConsumeAnnotationToken();
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
isAddressOfOperand = false;
E = Actions.ActOnNameClassifiedAsDependentNonType(SS, II, Loc,
isAddressOfOperand);
break;
}
case tok::annot_non_type_undeclared: {
assert(SS.isEmpty() &&
"undeclared non-type annotation should be unqualified");
IdentifierInfo *II = getIdentifierAnnotation(Tok);
SourceLocation Loc = ConsumeAnnotationToken();
E = Actions.ActOnNameClassifiedAsUndeclaredNonType(II, Loc);
break;
}
default:
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
if (ParseUnqualifiedId(SS, nullptr,
false,
false,
false,
false,
false, &TemplateKWLoc, Name))
return ExprError();
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
isAddressOfOperand = false;
E = Actions.ActOnIdExpression(
getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
isAddressOfOperand, nullptr, false,
&Replacement);
break;
}
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
checkPotentialAngleBracket(E);
return E;
}
ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, nullptr,
false,
false);
Token Replacement;
ExprResult Result =
tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
if (Result.isUnset()) {
UnconsumeToken(Replacement);
Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
}
assert(!Result.isUnset() && "Typo correction suggested a keyword replacement "
"for a previous keyword suggestion");
return Result;
}
ExprResult Parser::ParseLambdaExpression() {
LambdaIntroducer Intro;
if (ParseLambdaIntroducer(Intro)) {
SkipUntil(tok::r_square, StopAtSemi);
SkipUntil(tok::l_brace, StopAtSemi);
SkipUntil(tok::r_brace, StopAtSemi);
return ExprError();
}
return ParseLambdaExpressionAfterIntroducer(Intro);
}
ExprResult Parser::TryParseLambdaExpression() {
assert(getLangOpts().CPlusPlus11
&& Tok.is(tok::l_square)
&& "Not at the start of a possible lambda expression.");
const Token Next = NextToken();
if (Next.is(tok::eof)) return ExprEmpty();
const Token After = GetLookAheadToken(2);
if (Next.is(tok::r_square) || Next.is(tok::equal) || (Next.is(tok::amp) && After.isOneOf(tok::r_square, tok::comma)) ||
(Next.is(tok::identifier) && After.is(tok::r_square)) ||
Next.is(tok::ellipsis)) { return ParseLambdaExpression();
}
if (Next.is(tok::identifier) && After.is(tok::identifier))
return ExprEmpty();
LambdaIntroducer Intro;
{
TentativeParsingAction TPA(*this);
LambdaIntroducerTentativeParse Tentative;
if (ParseLambdaIntroducer(Intro, &Tentative)) {
TPA.Commit();
return ExprError();
}
switch (Tentative) {
case LambdaIntroducerTentativeParse::Success:
TPA.Commit();
break;
case LambdaIntroducerTentativeParse::Incomplete:
TPA.Revert();
Intro = LambdaIntroducer();
if (ParseLambdaIntroducer(Intro))
return ExprError();
break;
case LambdaIntroducerTentativeParse::MessageSend:
case LambdaIntroducerTentativeParse::Invalid:
TPA.Revert();
return ExprEmpty();
}
}
return ParseLambdaExpressionAfterIntroducer(Intro);
}
bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
LambdaIntroducerTentativeParse *Tentative) {
if (Tentative)
*Tentative = LambdaIntroducerTentativeParse::Success;
assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
Intro.Range.setBegin(T.getOpenLocation());
bool First = true;
auto Invalid = [&](llvm::function_ref<void()> Action) {
if (Tentative) {
*Tentative = LambdaIntroducerTentativeParse::Invalid;
return false;
}
Action();
return true;
};
auto NonTentativeAction = [&](llvm::function_ref<void()> Action) {
if (Tentative)
*Tentative = LambdaIntroducerTentativeParse::Incomplete;
else
Action();
};
if (Tok.is(tok::amp) &&
(NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
Intro.Default = LCD_ByRef;
Intro.DefaultLoc = ConsumeToken();
First = false;
if (!Tok.getIdentifierInfo()) {
Tentative = nullptr;
}
} else if (Tok.is(tok::equal)) {
Intro.Default = LCD_ByCopy;
Intro.DefaultLoc = ConsumeToken();
First = false;
Tentative = nullptr;
}
while (Tok.isNot(tok::r_square)) {
if (!First) {
if (Tok.isNot(tok::comma)) {
if (Tok.is(tok::code_completion) &&
!(getLangOpts().ObjC && Tentative)) {
cutOffParsing();
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
false);
break;
}
return Invalid([&] {
Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare);
});
}
ConsumeToken();
}
if (Tok.is(tok::code_completion)) {
cutOffParsing();
if (getLangOpts().ObjC && Tentative && First)
Actions.CodeCompleteObjCMessageReceiver(getCurScope());
else
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
false);
break;
}
First = false;
LambdaCaptureKind Kind = LCK_ByCopy;
LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit;
SourceLocation Loc;
IdentifierInfo *Id = nullptr;
SourceLocation EllipsisLocs[4];
ExprResult Init;
SourceLocation LocStart = Tok.getLocation();
if (Tok.is(tok::star)) {
Loc = ConsumeToken();
if (Tok.is(tok::kw_this)) {
ConsumeToken();
Kind = LCK_StarThis;
} else {
return Invalid([&] {
Diag(Tok.getLocation(), diag::err_expected_star_this_capture);
});
}
} else if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
Loc = ConsumeToken();
} else if (Tok.isOneOf(tok::amp, tok::equal) &&
NextToken().isOneOf(tok::comma, tok::r_square) &&
Intro.Default == LCD_None) {
return Invalid(
[&] { Diag(Tok.getLocation(), diag::err_capture_default_first); });
} else {
TryConsumeToken(tok::ellipsis, EllipsisLocs[0]);
if (Tok.is(tok::amp)) {
Kind = LCK_ByRef;
ConsumeToken();
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
true);
break;
}
}
TryConsumeToken(tok::ellipsis, EllipsisLocs[1]);
if (Tok.is(tok::identifier)) {
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
} else if (Tok.is(tok::kw_this)) {
return Invalid([&] {
Diag(Tok.getLocation(), diag::err_this_captured_by_reference);
});
} else {
return Invalid([&] {
Diag(Tok.getLocation(), diag::err_expected_capture);
});
}
TryConsumeToken(tok::ellipsis, EllipsisLocs[2]);
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
InitKind = LambdaCaptureInitKind::DirectInit;
ExprVector Exprs;
CommaLocsTy Commas;
if (Tentative) {
Parens.skipToEnd();
*Tentative = LambdaIntroducerTentativeParse::Incomplete;
} else if (ParseExpressionList(Exprs, Commas)) {
Parens.skipToEnd();
Init = ExprError();
} else {
Parens.consumeClose();
Init = Actions.ActOnParenListExpr(Parens.getOpenLocation(),
Parens.getCloseLocation(),
Exprs);
}
} else if (Tok.isOneOf(tok::l_brace, tok::equal)) {
EnterExpressionEvaluationContext EC(
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
if (TryConsumeToken(tok::equal))
InitKind = LambdaCaptureInitKind::CopyInit;
else
InitKind = LambdaCaptureInitKind::ListInit;
if (!Tentative) {
Init = ParseInitializer();
} else if (Tok.is(tok::l_brace)) {
BalancedDelimiterTracker Braces(*this, tok::l_brace);
Braces.consumeOpen();
Braces.skipToEnd();
*Tentative = LambdaIntroducerTentativeParse::Incomplete;
} else {
SourceLocation StartLoc = Tok.getLocation();
InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true);
Init = ParseInitializer();
if (!Init.isInvalid())
Init = Actions.CorrectDelayedTyposInExpr(Init.get());
if (Tok.getLocation() != StartLoc) {
PP.RevertCachedTokens(1);
Tok.setLocation(StartLoc);
Tok.setKind(tok::annot_primary_expr);
setExprAnnotation(Tok, Init);
Tok.setAnnotationEndLoc(PP.getLastCachedTokenLocation());
PP.AnnotateCachedTokens(Tok);
ConsumeAnnotationToken();
}
}
}
TryConsumeToken(tok::ellipsis, EllipsisLocs[3]);
}
if (Tentative && Tok.is(tok::identifier) &&
NextToken().isOneOf(tok::colon, tok::r_square)) {
*Tentative = LambdaIntroducerTentativeParse::MessageSend;
return false;
}
SourceLocation EllipsisLoc;
if (llvm::any_of(EllipsisLocs,
[](SourceLocation Loc) { return Loc.isValid(); })) {
bool InitCapture = InitKind != LambdaCaptureInitKind::NoInit;
SourceLocation *ExpectedEllipsisLoc =
!InitCapture ? &EllipsisLocs[2] :
Kind == LCK_ByRef ? &EllipsisLocs[1] :
&EllipsisLocs[0];
EllipsisLoc = *ExpectedEllipsisLoc;
unsigned DiagID = 0;
if (EllipsisLoc.isInvalid()) {
DiagID = diag::err_lambda_capture_misplaced_ellipsis;
for (SourceLocation Loc : EllipsisLocs) {
if (Loc.isValid())
EllipsisLoc = Loc;
}
} else {
unsigned NumEllipses = std::accumulate(
std::begin(EllipsisLocs), std::end(EllipsisLocs), 0,
[](int N, SourceLocation Loc) { return N + Loc.isValid(); });
if (NumEllipses > 1)
DiagID = diag::err_lambda_capture_multiple_ellipses;
}
if (DiagID) {
NonTentativeAction([&] {
SourceLocation DiagLoc;
for (SourceLocation &Loc : EllipsisLocs) {
if (&Loc != ExpectedEllipsisLoc && Loc.isValid()) {
DiagLoc = Loc;
break;
}
}
assert(DiagLoc.isValid() && "no location for diagnostic");
auto &&D = Diag(DiagLoc, DiagID);
if (DiagID == diag::err_lambda_capture_misplaced_ellipsis) {
SourceLocation ExpectedLoc =
InitCapture ? Loc
: Lexer::getLocForEndOfToken(
Loc, 0, PP.getSourceManager(), getLangOpts());
D << InitCapture << FixItHint::CreateInsertion(ExpectedLoc, "...");
}
for (SourceLocation &Loc : EllipsisLocs) {
if (&Loc != ExpectedEllipsisLoc && Loc.isValid())
D << FixItHint::CreateRemoval(Loc);
}
});
}
}
ParsedType InitCaptureType;
if (Init.isUsable())
Init = Actions.CorrectDelayedTyposInExpr(Init.get());
if (Init.isUsable()) {
NonTentativeAction([&] {
Expr *InitExpr = Init.get();
InitCaptureType = Actions.actOnLambdaInitCaptureInitialization(
Loc, Kind == LCK_ByRef, EllipsisLoc, Id, InitKind, InitExpr);
Init = InitExpr;
});
}
SourceLocation LocEnd = PrevTokLocation;
Intro.addCapture(Kind, Loc, Id, EllipsisLoc, InitKind, Init,
InitCaptureType, SourceRange(LocStart, LocEnd));
}
T.consumeClose();
Intro.Range.setEnd(T.getCloseLocation());
return false;
}
static void tryConsumeLambdaSpecifierToken(Parser &P,
SourceLocation &MutableLoc,
SourceLocation &ConstexprLoc,
SourceLocation &ConstevalLoc,
SourceLocation &DeclEndLoc) {
assert(MutableLoc.isInvalid());
assert(ConstexprLoc.isInvalid());
while (true) {
switch (P.getCurToken().getKind()) {
case tok::kw_mutable: {
if (MutableLoc.isValid()) {
P.Diag(P.getCurToken().getLocation(),
diag::err_lambda_decl_specifier_repeated)
<< 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
}
MutableLoc = P.ConsumeToken();
DeclEndLoc = MutableLoc;
break ;
}
case tok::kw_constexpr:
if (ConstexprLoc.isValid()) {
P.Diag(P.getCurToken().getLocation(),
diag::err_lambda_decl_specifier_repeated)
<< 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
}
ConstexprLoc = P.ConsumeToken();
DeclEndLoc = ConstexprLoc;
break ;
case tok::kw_consteval:
if (ConstevalLoc.isValid()) {
P.Diag(P.getCurToken().getLocation(),
diag::err_lambda_decl_specifier_repeated)
<< 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
}
ConstevalLoc = P.ConsumeToken();
DeclEndLoc = ConstevalLoc;
break ;
default:
return;
}
}
}
static void
addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
DeclSpec &DS) {
if (ConstexprLoc.isValid()) {
P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus17
? diag::ext_constexpr_on_lambda_cxx17
: diag::warn_cxx14_compat_constexpr_on_lambda);
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
DS.SetConstexprSpec(ConstexprSpecKind::Constexpr, ConstexprLoc, PrevSpec,
DiagID);
assert(PrevSpec == nullptr && DiagID == 0 &&
"Constexpr cannot have been set previously!");
}
}
static void addConstevalToLambdaDeclSpecifier(Parser &P,
SourceLocation ConstevalLoc,
DeclSpec &DS) {
if (ConstevalLoc.isValid()) {
P.Diag(ConstevalLoc, diag::warn_cxx20_compat_consteval);
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
DS.SetConstexprSpec(ConstexprSpecKind::Consteval, ConstevalLoc, PrevSpec,
DiagID);
if (DiagID != 0)
P.Diag(ConstevalLoc, DiagID) << PrevSpec;
}
}
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro) {
SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
"lambda expression parsing");
DeclSpec DS(AttrFactory);
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::LambdaExpr);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
Actions.PushLambdaScope();
ParsedAttributes Attr(AttrFactory);
if (getLangOpts().CUDA) {
MaybeParseGNUAttributes(D);
}
auto WarnIfHasCUDATargetAttr = [&] {
if (getLangOpts().CUDA)
for (const ParsedAttr &A : Attr)
if (A.getKind() == ParsedAttr::AT_CUDADevice ||
A.getKind() == ParsedAttr::AT_CUDAHost ||
A.getKind() == ParsedAttr::AT_CUDAGlobal)
Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position)
<< A.getAttrName()->getName();
};
MultiParseScope TemplateParamScope(*this);
if (Tok.is(tok::less)) {
Diag(Tok, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_lambda_template_parameter_list
: diag::ext_lambda_template_parameter_list);
SmallVector<NamedDecl*, 4> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
if (ParseTemplateParameters(TemplateParamScope,
CurTemplateDepthTracker.getDepth(),
TemplateParams, LAngleLoc, RAngleLoc)) {
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
}
if (TemplateParams.empty()) {
Diag(RAngleLoc,
diag::err_lambda_template_parameter_list_empty);
} else {
ExprResult RequiresClause;
if (TryConsumeToken(tok::kw_requires)) {
RequiresClause =
Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression(
false));
if (RequiresClause.isInvalid())
SkipUntil({tok::l_brace, tok::l_paren}, StopAtSemi | StopBeforeMatch);
}
Actions.ActOnLambdaExplicitTemplateParameterList(
LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
++CurTemplateDepthTracker;
}
}
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;
MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
SourceLocation MutableLoc;
SourceLocation ConstexprLoc;
SourceLocation ConstevalLoc;
tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
ConstevalLoc, DeclEndLoc);
addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
CachedTokens *ExceptionSpecTokens;
ESpecType = tryParseExceptionSpecification(
false, ESpecRange, DynamicExceptions,
DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens);
if (ESpecType != EST_None)
DeclEndLoc = ESpecRange.getEnd();
if (MaybeParseCXX11Attributes(Attr))
DeclEndLoc = Attr.Range.getEnd();
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;
if (Tok.is(tok::arrow)) {
FunLocalRangeEnd = Tok.getLocation();
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(
Range, false);
TrailingReturnTypeLoc = Range.getBegin();
if (Range.getEnd().isValid())
DeclEndLoc = Range.getEnd();
}
SourceLocation NoLoc;
D.AddTypeInfo(
DeclaratorChunk::getFunction(
true,
false, LParenLoc, ParamInfo.data(),
ParamInfo.size(), EllipsisLoc, RParenLoc,
true,
NoLoc, MutableLoc, ESpecType, ESpecRange,
DynamicExceptions.data(), DynamicExceptionRanges.data(),
DynamicExceptions.size(),
NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
nullptr,
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);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
SourceLocation LParenLoc = T.getOpenLocation();
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
if (Tok.isNot(tok::r_paren)) {
Actions.RecordParsingTemplateParameterDepth(
CurTemplateDepthTracker.getOriginalDepth());
ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo,
EllipsisLoc);
if (Actions.getCurGenericLambda())
CurTemplateDepthTracker.setAddedDepth(1);
}
T.consumeClose();
ParseLambdaSpecifiers(LParenLoc, T.getCloseLocation(),
ParamInfo, EllipsisLoc);
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
} 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_noexcept) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
if (!getLangOpts().CPlusPlus2b)
Diag(Tok, diag::ext_lambda_missing_parens)
<< FixItHint::CreateInsertion(Tok.getLocation(), "() ");
SourceLocation NoLoc;
std::vector<DeclaratorChunk::ParamInfo> EmptyParamInfo;
ParseLambdaSpecifiers(NoLoc, NoLoc,
EmptyParamInfo, NoLoc);
}
WarnIfHasCUDATargetAttr();
unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope;
ParseScope BodyScope(this, ScopeFlags);
Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lambda_body);
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
}
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
TemplateParamScope.Exit();
if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
}
ExprResult Parser::ParseCXXCasts() {
tok::TokenKind Kind = Tok.getKind();
const char *CastName = nullptr;
switch (Kind) {
default: llvm_unreachable("Unknown C++ cast!");
case tok::kw_addrspace_cast: CastName = "addrspace_cast"; break;
case tok::kw_const_cast: CastName = "const_cast"; break;
case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
case tok::kw_static_cast: CastName = "static_cast"; break;
}
SourceLocation OpLoc = ConsumeToken();
SourceLocation LAngleBracketLoc = Tok.getLocation();
if (Tok.is(tok::l_square) && Tok.getLength() == 2) {
Token Next = NextToken();
if (Next.is(tok::colon) && areTokensAdjacent(Tok, Next))
FixDigraph(*this, PP, Tok, Next, Kind, true);
}
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
return ExprError();
DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
ParseDeclarator(DeclaratorInfo);
SourceLocation RAngleBracketLoc = Tok.getLocation();
if (ExpectAndConsume(tok::greater))
return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less);
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, CastName))
return ExprError();
ExprResult Result = ParseExpression();
T.consumeClose();
if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType())
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
LAngleBracketLoc, DeclaratorInfo,
RAngleBracketLoc,
T.getOpenLocation(), Result.get(),
T.getCloseLocation());
return Result;
}
ExprResult Parser::ParseCXXTypeid() {
assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
SourceLocation OpLoc = ConsumeToken();
SourceLocation LParenLoc, RParenLoc;
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid"))
return ExprError();
LParenLoc = T.getOpenLocation();
ExprResult Result;
EnterExpressionEvaluationContext Unevaluated(
Actions, Sema::ExpressionEvaluationContext::Unevaluated,
Sema::ReuseLambdaContextDecl);
if (isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
T.consumeClose();
RParenLoc = T.getCloseLocation();
if (Ty.isInvalid() || RParenLoc.isInvalid())
return ExprError();
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, true,
Ty.get().getAsOpaquePtr(), RParenLoc);
} else {
Result = ParseExpression();
if (Result.isInvalid())
SkipUntil(tok::r_paren, StopAtSemi);
else {
T.consumeClose();
RParenLoc = T.getCloseLocation();
if (RParenLoc.isInvalid())
return ExprError();
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, false,
Result.get(), RParenLoc);
}
}
return Result;
}
ExprResult Parser::ParseCXXUuidof() {
assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!");
SourceLocation OpLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof"))
return ExprError();
ExprResult Result;
if (isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
T.consumeClose();
if (Ty.isInvalid())
return ExprError();
Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), true,
Ty.get().getAsOpaquePtr(),
T.getCloseLocation());
} else {
EnterExpressionEvaluationContext Unevaluated(
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
Result = ParseExpression();
if (Result.isInvalid())
SkipUntil(tok::r_paren, StopAtSemi);
else {
T.consumeClose();
Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(),
false,
Result.get(), T.getCloseLocation());
}
}
return Result;
}
ExprResult
Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
ParsedType ObjectType) {
UnqualifiedId FirstTypeName;
SourceLocation CCLoc;
if (Tok.is(tok::identifier)) {
FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
CCLoc = ConsumeToken();
} else if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->isInvalid())
return ExprError();
FirstTypeName.setTemplateId(TemplateId);
ConsumeAnnotationToken();
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
CCLoc = ConsumeToken();
} else {
assert(SS.isEmpty() && "missing last component of nested name specifier");
FirstTypeName.setIdentifier(nullptr, SourceLocation());
}
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
SourceLocation TildeLoc = ConsumeToken();
if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid()) {
DeclSpec DS(AttrFactory);
ParseDecltypeSpecifier(DS);
if (DS.getTypeSpecType() == TST_error)
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
TildeLoc, DS);
}
if (!Tok.is(tok::identifier)) {
Diag(Tok, diag::err_destructor_tilde_identifier);
return ExprError();
}
UnqualifiedId SecondTypeName;
IdentifierInfo *Name = Tok.getIdentifierInfo();
SourceLocation NameLoc = ConsumeToken();
SecondTypeName.setIdentifier(Name, NameLoc);
if (Tok.is(tok::less) &&
ParseUnqualifiedIdTemplateId(
SS, ObjectType, Base && Base->containsErrors(), SourceLocation(),
Name, NameLoc, false, SecondTypeName,
true))
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
SS, FirstTypeName, CCLoc, TildeLoc,
SecondTypeName);
}
ExprResult Parser::ParseCXXBoolLiteral() {
tok::TokenKind Kind = Tok.getKind();
return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
}
ExprResult Parser::ParseThrowExpression() {
assert(Tok.is(tok::kw_throw) && "Not throw!");
SourceLocation ThrowLoc = ConsumeToken();
switch (Tok.getKind()) { case tok::semi:
case tok::r_paren:
case tok::r_square:
case tok::r_brace:
case tok::colon:
case tok::comma:
return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, nullptr);
default:
ExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid()) return Expr;
return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.get());
}
}
ExprResult Parser::ParseCoyieldExpression() {
assert(Tok.is(tok::kw_co_yield) && "Not co_yield!");
SourceLocation Loc = ConsumeToken();
ExprResult Expr = Tok.is(tok::l_brace) ? ParseBraceInitializer()
: ParseAssignmentExpression();
if (!Expr.isInvalid())
Expr = Actions.ActOnCoyieldExpr(getCurScope(), Loc, Expr.get());
return Expr;
}
ExprResult Parser::ParseCXXThis() {
assert(Tok.is(tok::kw_this) && "Not 'this'!");
SourceLocation ThisLoc = ConsumeToken();
return Actions.ActOnCXXThis(ThisLoc);
}
ExprResult
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::FunctionalCast);
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
assert((Tok.is(tok::l_paren) ||
(getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)))
&& "Expected '(' or '{'!");
if (Tok.is(tok::l_brace)) {
PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get());
ExprResult Init = ParseBraceInitializer();
if (Init.isInvalid())
return Init;
Expr *InitList = Init.get();
return Actions.ActOnCXXTypeConstructExpr(
TypeRep, InitList->getBeginLoc(), MultiExprArg(&InitList, 1),
InitList->getEndLoc(), true);
} else {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get());
ExprVector Exprs;
CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() {
QualType PreferredType;
if (TypeRep)
PreferredType = Actions.ProduceConstructorSignatureHelp(
TypeRep.get()->getCanonicalTypeInternal(), DS.getEndLoc(), Exprs,
T.getOpenLocation(), false);
CalledSignatureHelp = true;
return PreferredType;
};
if (Tok.isNot(tok::r_paren)) {
if (ParseExpressionList(Exprs, CommaLocs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
RunSignatureHelp();
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
}
T.consumeClose();
if (!TypeRep)
return ExprError();
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
Exprs, T.getCloseLocation(),
false);
}
}
Parser::DeclGroupPtrTy
Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
ParsedAttributes &Attrs) {
assert(Tok.is(tok::kw_using) && "Expected using");
assert((Context == DeclaratorContext::ForInit ||
Context == DeclaratorContext::SelectionInit) &&
"Unexpected Declarator Context");
DeclGroupPtrTy DG;
SourceLocation DeclStart = ConsumeToken(), DeclEnd;
DG = ParseUsingDeclaration(Context, {}, DeclStart, DeclEnd, Attrs, AS_none);
if (!DG)
return DG;
Diag(DeclStart, !getLangOpts().CPlusPlus2b
? diag::ext_alias_in_init_statement
: diag::warn_cxx20_alias_in_init_statement)
<< SourceRange(DeclStart, DeclEnd);
return DG;
}
Sema::ConditionResult
Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
Sema::ConditionKind CK, bool MissingOK,
ForRangeInfo *FRI, bool EnterForConditionScope) {
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)) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
return Sema::ConditionError();
}
ParsedAttributes attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
const auto WarnOnInit = [this, &CK] {
Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
? diag::warn_cxx14_compat_init_statement
: diag::ext_init_statement)
<< (CK == Sema::ConditionKind::Switch);
};
switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) {
case ConditionOrInitStatement::Expression: {
ForConditionScope.enter(false);
ProhibitAttributes(attrs);
if (InitStmt && Tok.is(tok::semi)) {
WarnOnInit();
SourceLocation SemiLoc = Tok.getLocation();
if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID()) {
Diag(SemiLoc, diag::warn_empty_init_statement)
<< (CK == Sema::ConditionKind::Switch)
<< FixItHint::CreateRemoval(SemiLoc);
}
ConsumeToken();
*InitStmt = Actions.ActOnNullStmt(SemiLoc);
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
}
ExprResult Expr = ParseExpression(); if (Expr.isInvalid())
return Sema::ConditionError();
if (InitStmt && Tok.is(tok::semi)) {
WarnOnInit();
*InitStmt = Actions.ActOnExprStmt(Expr.get());
ConsumeToken();
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
}
return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK,
MissingOK);
}
case ConditionOrInitStatement::InitStmtDecl: {
WarnOnInit();
DeclGroupPtrTy DG;
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
if (Tok.is(tok::kw_using))
DG = ParseAliasDeclarationInInitStatement(
DeclaratorContext::SelectionInit, attrs);
else {
ParsedAttributes DeclSpecAttrs(AttrFactory);
DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd,
attrs, DeclSpecAttrs, true);
}
*InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
}
case ConditionOrInitStatement::ForRangeDecl: {
assert(FRI && "should not parse a for range declaration here");
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
ParsedAttributes DeclSpecAttrs(AttrFactory);
DeclGroupPtrTy DG = ParseSimpleDeclaration(
DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false, FRI);
FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
assert((FRI->ColonLoc.isValid() || !DG) &&
"cannot find for range declaration");
return Sema::ConditionResult();
}
case ConditionOrInitStatement::ConditionDecl:
case ConditionOrInitStatement::Error:
break;
}
ForConditionScope.enter(true);
DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition);
Declarator DeclaratorInfo(DS, attrs, DeclaratorContext::Condition);
ParseDeclarator(DeclaratorInfo);
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
ExprResult AsmLabel(ParseSimpleAsm( true, &Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopAtSemi);
return Sema::ConditionError();
}
DeclaratorInfo.setAsmLabel(AsmLabel.get());
DeclaratorInfo.SetRangeEnd(Loc);
}
MaybeParseGNUAttributes(DeclaratorInfo);
DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(),
DeclaratorInfo);
if (Dcl.isInvalid())
return Sema::ConditionError();
Decl *DeclOut = Dcl.get();
bool CopyInitialization = isTokenEqualOrEqualTypo();
if (CopyInitialization)
ConsumeToken();
ExprResult InitExpr = ExprError();
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
InitExpr = ParseBraceInitializer();
} else if (CopyInitialization) {
PreferredType.enterVariableInit(Tok.getLocation(), DeclOut);
InitExpr = ParseAssignmentExpression();
} else if (Tok.is(tok::l_paren)) {
SourceLocation LParen = ConsumeParen(), RParen = LParen;
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch))
RParen = ConsumeParen();
Diag(DeclOut->getLocation(),
diag::err_expected_init_in_condition_lparen)
<< SourceRange(LParen, RParen);
} else {
Diag(DeclOut->getLocation(), diag::err_expected_init_in_condition);
}
if (!InitExpr.isInvalid())
Actions.AddInitializerToDecl(DeclOut, InitExpr.get(), !CopyInitialization);
else
Actions.ActOnInitializerError(DeclOut);
Actions.FinalizeDeclaration(DeclOut);
return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
}
void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetRangeStart(Tok.getLocation());
const char *PrevSpec;
unsigned DiagID;
SourceLocation Loc = Tok.getLocation();
const clang::PrintingPolicy &Policy =
Actions.getASTContext().getPrintingPolicy();
switch (Tok.getKind()) {
case tok::identifier: case tok::coloncolon: llvm_unreachable("Annotation token should already be formed!");
default:
llvm_unreachable("Not a simple-type-specifier token!");
case tok::annot_typename: {
DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID,
getTypeAnnotation(Tok), Policy);
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeAnnotationToken();
DS.Finish(Actions, Policy);
return;
}
case tok::kw__ExtInt:
case tok::kw__BitInt: {
DiagnoseBitIntUse(Tok);
ExprResult ER = ParseExtIntegerArgument();
if (ER.isInvalid())
DS.SetTypeSpecError();
else
DS.SetBitIntType(Loc, ER.get(), PrevSpec, DiagID, Policy);
DS.SetRangeEnd(PrevTokLocation);
DS.Finish(Actions, Policy);
return;
}
case tok::kw_short:
DS.SetTypeSpecWidth(TypeSpecifierWidth::Short, Loc, PrevSpec, DiagID,
Policy);
break;
case tok::kw_long:
DS.SetTypeSpecWidth(TypeSpecifierWidth::Long, Loc, PrevSpec, DiagID,
Policy);
break;
case tok::kw___int64:
DS.SetTypeSpecWidth(TypeSpecifierWidth::LongLong, Loc, PrevSpec, DiagID,
Policy);
break;
case tok::kw_signed:
DS.SetTypeSpecSign(TypeSpecifierSign::Signed, Loc, PrevSpec, DiagID);
break;
case tok::kw_unsigned:
DS.SetTypeSpecSign(TypeSpecifierSign::Unsigned, Loc, PrevSpec, DiagID);
break;
case tok::kw_void:
DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_auto:
DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char:
DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_int:
DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___int128:
DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___bf16:
DS.SetTypeSpecType(DeclSpec::TST_BFloat16, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_half:
DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_float:
DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_double:
DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw__Float16:
DS.SetTypeSpecType(DeclSpec::TST_float16, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___float128:
DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___ibm128:
DS.SetTypeSpecType(DeclSpec::TST_ibm128, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_wchar_t:
DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char8_t:
DS.SetTypeSpecType(DeclSpec::TST_char8, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char16_t:
DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char32_t:
DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_bool:
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy);
break;
#define GENERIC_IMAGE_TYPE(ImgType, Id) \
case tok::kw_##ImgType##_t: \
DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, DiagID, \
Policy); \
break;
#include "clang/Basic/OpenCLImageTypes.def"
case tok::annot_decltype:
case tok::kw_decltype:
DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
return DS.Finish(Actions, Policy);
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
DS.Finish(Actions, Policy);
return;
}
ConsumeAnyToken();
DS.SetRangeEnd(PrevTokLocation);
DS.Finish(Actions, Policy);
}
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_type_specifier);
DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
return false;
}
bool Parser::ParseUnqualifiedIdTemplateId(
CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc,
bool EnteringContext, UnqualifiedId &Id, bool AssumeTemplateId) {
assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
TemplateTy Template;
TemplateNameKind TNK = TNK_Non_template;
switch (Id.getKind()) {
case UnqualifiedIdKind::IK_Identifier:
case UnqualifiedIdKind::IK_OperatorFunctionId:
case UnqualifiedIdKind::IK_LiteralOperatorId:
if (AssumeTemplateId) {
TNK = Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Id,
ObjectType, EnteringContext, Template,
true);
} else {
bool MemberOfUnknownSpecialization;
TNK = Actions.isTemplateName(getCurScope(), SS,
TemplateKWLoc.isValid(), Id,
ObjectType, EnteringContext, Template,
MemberOfUnknownSpecialization);
if (TNK == TNK_Undeclared_template &&
isTemplateArgumentList(0) == TPResult::False)
return false;
if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&
ObjectType && isTemplateArgumentList(0) == TPResult::True) {
if (!ObjectHadErrors) {
std::string Name;
if (Id.getKind() == UnqualifiedIdKind::IK_Identifier)
Name = std::string(Id.Identifier->getName());
else {
Name = "operator ";
if (Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId)
Name += getOperatorSpelling(Id.OperatorFunctionId.Operator);
else
Name += Id.Identifier->getName();
}
Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
<< Name
<< FixItHint::CreateInsertion(Id.StartLocation, "template ");
}
TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
Template, true);
} else if (TNK == TNK_Non_template) {
return false;
}
}
break;
case UnqualifiedIdKind::IK_ConstructorName: {
UnqualifiedId TemplateName;
bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
TemplateName, ObjectType,
EnteringContext, Template,
MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template)
return false;
break;
}
case UnqualifiedIdKind::IK_DestructorName: {
UnqualifiedId TemplateName;
bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
EnteringContext, Template, true);
} else {
TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
TemplateName, ObjectType,
EnteringContext, Template,
MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && !Id.DestructorName.get()) {
Diag(NameLoc, diag::err_destructor_template_id)
<< Name << SS.getRange();
}
}
break;
}
default:
return false;
}
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs, RAngleLoc,
Template))
return true;
if (TNK == TNK_Non_template)
return true;
if (Id.getKind() == UnqualifiedIdKind::IK_Identifier ||
Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
Id.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) {
IdentifierInfo *TemplateII =
Id.getKind() == UnqualifiedIdKind::IK_Identifier ? Id.Identifier
: nullptr;
OverloadedOperatorKind OpKind =
Id.getKind() == UnqualifiedIdKind::IK_Identifier
? OO_None
: Id.OperatorFunctionId.Operator;
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
LAngleLoc, RAngleLoc, TemplateArgs, false, TemplateIds);
Id.setTemplateId(TemplateId);
return false;
}
ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
TypeResult Type = Actions.ActOnTemplateIdType(
getCurScope(), SS, TemplateKWLoc, Template, Name, NameLoc, LAngleLoc,
TemplateArgsPtr, RAngleLoc, true);
if (Type.isInvalid())
return true;
if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName)
Id.setConstructorName(Type.get(), NameLoc, RAngleLoc);
else
Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc);
return false;
}
bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result) {
assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
SourceLocation KeywordLoc = ConsumeToken();
unsigned SymbolIdx = 0;
SourceLocation SymbolLocations[3];
OverloadedOperatorKind Op = OO_None;
switch (Tok.getKind()) {
case tok::kw_new:
case tok::kw_delete: {
bool isNew = Tok.getKind() == tok::kw_new;
SymbolLocations[SymbolIdx++] = ConsumeToken();
if (Tok.is(tok::l_square) &&
(!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))) {
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
T.consumeClose();
if (T.getCloseLocation().isInvalid())
return true;
SymbolLocations[SymbolIdx++] = T.getOpenLocation();
SymbolLocations[SymbolIdx++] = T.getCloseLocation();
Op = isNew? OO_Array_New : OO_Array_Delete;
} else {
Op = isNew? OO_New : OO_Delete;
}
break;
}
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case tok::Token: \
SymbolLocations[SymbolIdx++] = ConsumeToken(); \
Op = OO_##Name; \
break;
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
#include "clang/Basic/OperatorKinds.def"
case tok::l_paren: {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
T.consumeClose();
if (T.getCloseLocation().isInvalid())
return true;
SymbolLocations[SymbolIdx++] = T.getOpenLocation();
SymbolLocations[SymbolIdx++] = T.getCloseLocation();
Op = OO_Call;
break;
}
case tok::l_square: {
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
T.consumeClose();
if (T.getCloseLocation().isInvalid())
return true;
SymbolLocations[SymbolIdx++] = T.getOpenLocation();
SymbolLocations[SymbolIdx++] = T.getCloseLocation();
Op = OO_Subscript;
break;
}
case tok::code_completion: {
cutOffParsing();
Actions.CodeCompleteOperatorName(getCurScope());
return true;
}
default:
break;
}
if (Op != OO_None) {
Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
return false;
}
if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
SourceLocation DiagLoc;
unsigned DiagId = 0;
SmallVector<Token, 4> Toks;
SmallVector<SourceLocation, 4> TokLocs;
while (isTokenStringLiteral()) {
if (!Tok.is(tok::string_literal) && !DiagId) {
DiagLoc = Tok.getLocation();
DiagId = diag::err_literal_operator_string_prefix;
}
Toks.push_back(Tok);
TokLocs.push_back(ConsumeStringToken());
}
StringLiteralParser Literal(Toks, PP);
if (Literal.hadError)
return true;
bool IsUDSuffix = !Literal.getUDSuffix().empty();
IdentifierInfo *II = nullptr;
SourceLocation SuffixLoc;
if (IsUDSuffix) {
II = &PP.getIdentifierTable().get(Literal.getUDSuffix());
SuffixLoc =
Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
Literal.getUDSuffixOffset(),
PP.getSourceManager(), getLangOpts());
} else if (Tok.is(tok::identifier)) {
II = Tok.getIdentifierInfo();
SuffixLoc = ConsumeToken();
TokLocs.push_back(SuffixLoc);
} else {
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
return true;
}
if (!Literal.GetString().empty() || Literal.Pascal) {
DiagLoc = TokLocs.front();
DiagId = diag::err_literal_operator_string_not_empty;
}
if (DiagId) {
SmallString<32> Str;
Str += "\"\"";
Str += II->getName();
Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement(
SourceRange(TokLocs.front(), TokLocs.back()), Str);
}
Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
return Actions.checkLiteralOperatorId(SS, Result, IsUDSuffix);
}
DeclSpec DS(AttrFactory);
if (ParseCXXTypeSpecifierSeq(DS)) return true;
Declarator D(DS, ParsedAttributesView::none(),
DeclaratorContext::ConversionId);
ParseDeclaratorInternal(D, nullptr);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D);
if (Ty.isInvalid())
return true;
Result.setConversionFunctionId(KeywordLoc, Ty.get(),
D.getSourceRange().getEnd());
return false;
}
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
bool ObjectHadErrors, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
bool AllowDeductionGuide,
SourceLocation *TemplateKWLoc,
UnqualifiedId &Result) {
if (TemplateKWLoc)
*TemplateKWLoc = SourceLocation();
bool TemplateSpecified = false;
if (Tok.is(tok::kw_template)) {
if (TemplateKWLoc && (ObjectType || SS.isSet())) {
TemplateSpecified = true;
*TemplateKWLoc = ConsumeToken();
} else {
SourceLocation TemplateLoc = ConsumeToken();
Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id)
<< FixItHint::CreateRemoval(TemplateLoc);
}
}
if (Tok.is(tok::identifier)) {
IdentifierInfo *Id = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
if (!getLangOpts().CPlusPlus) {
Result.setIdentifier(Id, IdLoc);
return false;
}
ParsedTemplateTy TemplateName;
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
ParsedType Ty = Actions.getConstructorName(*Id, IdLoc, getCurScope(), SS,
EnteringContext);
if (!Ty)
return true;
Result.setConstructorName(Ty, IdLoc, IdLoc);
} else if (getLangOpts().CPlusPlus17 &&
AllowDeductionGuide && SS.isEmpty() &&
Actions.isDeductionGuideName(getCurScope(), *Id, IdLoc,
&TemplateName)) {
Result.setDeductionGuideName(TemplateName, IdLoc);
} else {
Result.setIdentifier(Id, IdLoc);
}
TemplateTy Template;
if (Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(
SS, ObjectType, ObjectHadErrors,
TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc,
EnteringContext, Result, TemplateSpecified);
else if (TemplateSpecified &&
Actions.ActOnTemplateName(
getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
EnteringContext, Template,
true) == TNK_Non_template)
return true;
return false;
}
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->isInvalid()) {
ConsumeAnnotationToken();
return true;
}
if (AllowConstructorName && TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
if (SS.isSet()) {
Diag(TemplateId->TemplateNameLoc,
diag::err_out_of_line_constructor_template_id)
<< TemplateId->Name
<< FixItHint::CreateRemoval(
SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
ParsedType Ty = Actions.getConstructorName(
*TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), SS,
EnteringContext);
if (!Ty)
return true;
Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
ConsumeAnnotationToken();
return false;
}
Result.setConstructorTemplateId(TemplateId);
ConsumeAnnotationToken();
return false;
}
Result.setTemplateId(TemplateId);
SourceLocation TemplateLoc = TemplateId->TemplateKWLoc;
if (TemplateLoc.isValid()) {
if (TemplateKWLoc && (ObjectType || SS.isSet()))
*TemplateKWLoc = TemplateLoc;
else
Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id)
<< FixItHint::CreateRemoval(TemplateLoc);
}
ConsumeAnnotationToken();
return false;
}
if (Tok.is(tok::kw_operator)) {
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
return true;
TemplateTy Template;
if ((Result.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
Result.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) &&
Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(
SS, ObjectType, ObjectHadErrors,
TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr,
SourceLocation(), EnteringContext, Result, TemplateSpecified);
else if (TemplateSpecified &&
Actions.ActOnTemplateName(
getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
EnteringContext, Template,
true) == TNK_Non_template)
return true;
return false;
}
if (getLangOpts().CPlusPlus &&
(AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
SourceLocation TildeLoc = ConsumeToken();
if (TemplateSpecified) {
Diag(*TemplateKWLoc, diag::err_unexpected_template_in_destructor_name)
<< Tok.getLocation();
return true;
}
if (SS.isEmpty() && Tok.is(tok::kw_decltype)) {
DeclSpec DS(AttrFactory);
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
if (ParsedType Type =
Actions.getDestructorTypeForDecltype(DS, ObjectType)) {
Result.setDestructorName(TildeLoc, Type, EndLoc);
return false;
}
return true;
}
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_destructor_tilde_identifier);
return true;
}
DeclaratorScopeObj DeclScopeObj(*this, SS);
if (NextToken().is(tok::coloncolon)) {
ColonProtectionRAIIObject ColonRAII(*this, false);
if (SS.isSet()) {
AnnotateScopeToken(SS, true);
SS.clear();
}
if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, ObjectHadErrors,
EnteringContext))
return true;
if (SS.isNotEmpty())
ObjectType = nullptr;
if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) ||
!SS.isSet()) {
Diag(TildeLoc, diag::err_destructor_tilde_scope);
return true;
}
Diag(TildeLoc, diag::err_destructor_tilde_scope)
<< FixItHint::CreateRemoval(TildeLoc)
<< FixItHint::CreateInsertion(Tok.getLocation(), "~");
if (Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
DeclScopeObj.EnterDeclaratorScope();
}
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
SourceLocation ClassNameLoc = ConsumeToken();
if (Tok.is(tok::less)) {
Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
return ParseUnqualifiedIdTemplateId(
SS, ObjectType, ObjectHadErrors,
TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), ClassName,
ClassNameLoc, EnteringContext, Result, TemplateSpecified);
}
ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName,
ClassNameLoc, getCurScope(),
SS, ObjectType,
EnteringContext);
if (!Ty)
return true;
Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
return false;
}
Diag(Tok, diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
return true;
}
ExprResult
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
assert(Tok.is(tok::kw_new) && "expected 'new' token");
ConsumeToken();
ExprVector PlacementArgs;
SourceLocation PlacementLParen, PlacementRParen;
SourceRange TypeIdParens;
DeclSpec DS(AttrFactory);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::CXXNew);
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
PlacementLParen = T.getOpenLocation();
if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
T.consumeClose();
PlacementRParen = T.getCloseLocation();
if (PlacementRParen.isInvalid()) {
SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
if (PlacementArgs.empty()) {
TypeIdParens = T.getRange();
PlacementLParen = PlacementRParen = SourceLocation();
} else {
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
MaybeParseGNUAttributes(DeclaratorInfo);
ParseSpecifierQualifierList(DS);
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclarator(DeclaratorInfo);
T.consumeClose();
TypeIdParens = T.getRange();
} else {
MaybeParseGNUAttributes(DeclaratorInfo);
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else {
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclaratorInternal(DeclaratorInfo,
&Parser::ParseDirectNewDeclarator);
}
}
}
} else {
MaybeParseGNUAttributes(DeclaratorInfo);
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else {
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclaratorInternal(DeclaratorInfo,
&Parser::ParseDirectNewDeclarator);
}
}
if (DeclaratorInfo.isInvalidType()) {
SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
ExprResult Initializer;
if (Tok.is(tok::l_paren)) {
SourceLocation ConstructorLParen, ConstructorRParen;
ExprVector ConstructorArgs;
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ConstructorLParen = T.getOpenLocation();
if (Tok.isNot(tok::r_paren)) {
CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() {
ParsedType TypeRep =
Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
QualType PreferredType;
if (TypeRep)
PreferredType = Actions.ProduceConstructorSignatureHelp(
TypeRep.get()->getCanonicalTypeInternal(),
DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen,
false);
CalledSignatureHelp = true;
return PreferredType;
};
if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
RunSignatureHelp();
SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
}
T.consumeClose();
ConstructorRParen = T.getCloseLocation();
if (ConstructorRParen.isInvalid()) {
SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
ConstructorRParen,
ConstructorArgs);
} else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
Initializer = ParseBraceInitializer();
}
if (Initializer.isInvalid())
return Initializer;
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
PlacementArgs, PlacementRParen,
TypeIdParens, DeclaratorInfo, Initializer.get());
}
void Parser::ParseDirectNewDeclarator(Declarator &D) {
bool First = true;
while (Tok.is(tok::l_square)) {
if (CheckProhibitedCXX11Attribute())
continue;
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
ExprResult Size =
First ? (Tok.is(tok::r_square) ? ExprResult() : ParseExpression())
: ParseConstantExpression();
if (Size.isInvalid()) {
SkipUntil(tok::r_square, StopAtSemi);
return;
}
First = false;
T.consumeClose();
ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
D.AddTypeInfo(DeclaratorChunk::getArray(0,
false, false,
Size.get(), T.getOpenLocation(),
T.getCloseLocation()),
std::move(Attrs), T.getCloseLocation());
if (T.getCloseLocation().isInvalid())
return;
}
}
bool Parser::ParseExpressionListOrTypeId(
SmallVectorImpl<Expr*> &PlacementArgs,
Declarator &D) {
if (isTypeIdInParens()) {
ParseSpecifierQualifierList(D.getMutableDeclSpec());
D.SetSourceRange(D.getDeclSpec().getSourceRange());
ParseDeclarator(D);
return D.isInvalidType();
}
CommaLocsTy CommaLocs;
return ParseExpressionList(PlacementArgs, CommaLocs);
}
ExprResult
Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
ConsumeToken();
bool ArrayDelete = false;
if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) {
const Token Next = GetLookAheadToken(2);
if (Next.isOneOf(tok::l_brace, tok::less) ||
(Next.is(tok::l_paren) &&
(GetLookAheadToken(3).is(tok::r_paren) ||
(GetLookAheadToken(3).is(tok::identifier) &&
GetLookAheadToken(4).is(tok::identifier))))) {
TentativeParsingAction TPA(*this);
SourceLocation LSquareLoc = Tok.getLocation();
SourceLocation RSquareLoc = NextToken().getLocation();
SkipUntil({tok::l_brace, tok::less}, StopBeforeMatch);
SourceLocation RBraceLoc;
bool EmitFixIt = false;
if (Tok.is(tok::l_brace)) {
ConsumeBrace();
SkipUntil(tok::r_brace, StopBeforeMatch);
RBraceLoc = Tok.getLocation();
EmitFixIt = true;
}
TPA.Revert();
if (EmitFixIt)
Diag(Start, diag::err_lambda_after_delete)
<< SourceRange(Start, RSquareLoc)
<< FixItHint::CreateInsertion(LSquareLoc, "(")
<< FixItHint::CreateInsertion(
Lexer::getLocForEndOfToken(
RBraceLoc, 0, Actions.getSourceManager(), getLangOpts()),
")");
else
Diag(Start, diag::err_lambda_after_delete)
<< SourceRange(Start, RSquareLoc);
ExprResult Lambda = ParseLambdaExpression();
if (Lambda.isInvalid())
return ExprError();
Lambda = ParsePostfixExpressionSuffix(Lambda);
if (Lambda.isInvalid())
return ExprError();
return Actions.ActOnCXXDelete(Start, UseGlobal, false,
Lambda.get());
}
ArrayDelete = true;
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
T.consumeClose();
if (T.getCloseLocation().isInvalid())
return ExprError();
}
ExprResult Operand(ParseCastExpression(AnyCastExpr));
if (Operand.isInvalid())
return Operand;
return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get());
}
ExprResult Parser::ParseRequiresExpression() {
assert(Tok.is(tok::kw_requires) && "Expected 'requires' keyword");
SourceLocation RequiresKWLoc = ConsumeToken();
llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls;
if (Tok.is(tok::l_paren)) {
ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope |
Scope::DeclScope);
BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
if (!Tok.is(tok::r_paren)) {
ParsedAttributes FirstArgAttrs(getAttrFactory());
SourceLocation EllipsisLoc;
llvm::SmallVector<DeclaratorChunk::ParamInfo, 2> LocalParameters;
ParseParameterDeclarationClause(DeclaratorContext::RequiresExpr,
FirstArgAttrs, LocalParameters,
EllipsisLoc);
if (EllipsisLoc.isValid())
Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis);
for (auto &ParamInfo : LocalParameters)
LocalParameterDecls.push_back(cast<ParmVarDecl>(ParamInfo.Param));
}
Parens.consumeClose();
}
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.expectAndConsume())
return ExprError();
llvm::SmallVector<concepts::Requirement *, 2> Requirements;
EnterExpressionEvaluationContext Ctx(
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
ParseScope BodyScope(this, Scope::DeclScope);
RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(
RequiresKWLoc, LocalParameterDecls, getCurScope());
if (Tok.is(tok::r_brace)) {
Diag(Tok, diag::err_empty_requires_expr);
} else {
while (!Tok.is(tok::r_brace)) {
switch (Tok.getKind()) {
case tok::l_brace: {
BalancedDelimiterTracker ExprBraces(*this, tok::l_brace);
ExprBraces.consumeOpen();
ExprResult Expression =
Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (!Expression.isUsable()) {
ExprBraces.skipToEnd();
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
if (ExprBraces.consumeClose())
ExprBraces.skipToEnd();
concepts::Requirement *Req = nullptr;
SourceLocation NoexceptLoc;
TryConsumeToken(tok::kw_noexcept, NoexceptLoc);
if (Tok.is(tok::semi)) {
Req = Actions.ActOnCompoundRequirement(Expression.get(), NoexceptLoc);
if (Req)
Requirements.push_back(Req);
break;
}
if (!TryConsumeToken(tok::arrow))
Diag(Tok, diag::err_requires_expr_missing_arrow)
<< FixItHint::CreateInsertion(Tok.getLocation(), "->");
if (TryAnnotateTypeConstraint()) {
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
if (!isTypeConstraintAnnotation()) {
Diag(Tok, diag::err_requires_expr_expected_type_constraint);
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
CXXScopeSpec SS;
if (Tok.is(tok::annot_cxxscope)) {
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
ConsumeAnnotationToken();
}
Req = Actions.ActOnCompoundRequirement(
Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok),
TemplateParameterDepth);
ConsumeAnnotationToken();
if (Req)
Requirements.push_back(Req);
break;
}
default: {
bool PossibleRequiresExprInSimpleRequirement = false;
if (Tok.is(tok::kw_requires)) {
auto IsNestedRequirement = [&] {
RevertingTentativeParsingAction TPA(*this);
ConsumeToken(); if (Tok.is(tok::l_brace))
return false;
if (Tok.is(tok::l_paren)) {
ConsumeParen();
auto Res = TryParseParameterDeclarationClause();
if (Res != TPResult::False) {
unsigned Depth = 1;
while (Depth != 0) {
if (Tok.is(tok::l_paren))
Depth++;
else if (Tok.is(tok::r_paren))
Depth--;
ConsumeAnyToken();
}
if (Tok.is(tok::l_brace))
return false;
}
}
return true;
};
if (IsNestedRequirement()) {
ConsumeToken();
ExprResult ConstraintExpr =
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) {
SkipUntil(tok::semi, tok::r_brace,
SkipUntilFlags::StopBeforeMatch);
break;
}
if (auto *Req =
Actions.ActOnNestedRequirement(ConstraintExpr.get()))
Requirements.push_back(Req);
else {
SkipUntil(tok::semi, tok::r_brace,
SkipUntilFlags::StopBeforeMatch);
break;
}
break;
} else
PossibleRequiresExprInSimpleRequirement = true;
} else if (Tok.is(tok::kw_typename)) {
TentativeParsingAction TPA(*this);
SourceLocation TypenameKWLoc = ConsumeToken();
if (TryAnnotateOptionalCXXScopeToken()) {
TPA.Commit();
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
CXXScopeSpec SS;
if (Tok.is(tok::annot_cxxscope)) {
Actions.RestoreNestedNameSpecifierAnnotation(
Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS);
ConsumeAnnotationToken();
}
if (Tok.isOneOf(tok::identifier, tok::annot_template_id) &&
!NextToken().isOneOf(tok::l_brace, tok::l_paren)) {
TPA.Commit();
SourceLocation NameLoc = Tok.getLocation();
IdentifierInfo *II = nullptr;
TemplateIdAnnotation *TemplateId = nullptr;
if (Tok.is(tok::identifier)) {
II = Tok.getIdentifierInfo();
ConsumeToken();
} else {
TemplateId = takeTemplateIdAnnotation(Tok);
ConsumeAnnotationToken();
if (TemplateId->isInvalid())
break;
}
if (auto *Req = Actions.ActOnTypeRequirement(TypenameKWLoc, SS,
NameLoc, II,
TemplateId)) {
Requirements.push_back(Req);
}
break;
}
TPA.Revert();
}
SourceLocation StartLoc = Tok.getLocation();
ExprResult Expression =
Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (!Expression.isUsable()) {
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
if (!Expression.isInvalid() && PossibleRequiresExprInSimpleRequirement)
Diag(StartLoc, diag::err_requires_expr_in_simple_requirement)
<< FixItHint::CreateInsertion(StartLoc, "requires");
if (auto *Req = Actions.ActOnSimpleRequirement(Expression.get()))
Requirements.push_back(Req);
else {
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
if (Tok.is(tok::kw_noexcept)) {
Diag(Tok, diag::err_requires_expr_simple_requirement_noexcept)
<< FixItHint::CreateInsertion(StartLoc, "{")
<< FixItHint::CreateInsertion(Tok.getLocation(), "}");
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
}
break;
}
}
if (ExpectAndConsumeSemi(diag::err_expected_semi_requirement)) {
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
TryConsumeToken(tok::semi);
break;
}
}
if (Requirements.empty()) {
Braces.consumeClose();
Actions.ActOnFinishRequiresExpr();
return ExprError();
}
}
Braces.consumeClose();
Actions.ActOnFinishRequiresExpr();
return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls,
Requirements, Braces.getCloseLocation());
}
static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {
switch (kind) {
default: llvm_unreachable("Not a known type trait");
#define TYPE_TRAIT_1(Spelling, Name, Key) \
case tok::kw_ ## Spelling: return UTT_ ## Name;
#define TYPE_TRAIT_2(Spelling, Name, Key) \
case tok::kw_ ## Spelling: return BTT_ ## Name;
#include "clang/Basic/TokenKinds.def"
#define TYPE_TRAIT_N(Spelling, Name, Key) \
case tok::kw_ ## Spelling: return TT_ ## Name;
#include "clang/Basic/TokenKinds.def"
}
}
static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) {
switch (kind) {
default:
llvm_unreachable("Not a known array type trait");
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) \
case tok::kw_##Spelling: \
return ATT_##Name;
#include "clang/Basic/TokenKinds.def"
}
}
static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
switch (kind) {
default:
llvm_unreachable("Not a known unary expression trait.");
#define EXPRESSION_TRAIT(Spelling, Name, Key) \
case tok::kw_##Spelling: \
return ET_##Name;
#include "clang/Basic/TokenKinds.def"
}
}
static unsigned TypeTraitArity(tok::TokenKind kind) {
switch (kind) {
default: llvm_unreachable("Not a known type trait");
#define TYPE_TRAIT(N,Spelling,K) case tok::kw_##Spelling: return N;
#include "clang/Basic/TokenKinds.def"
}
}
ExprResult Parser::ParseTypeTrait() {
tok::TokenKind Kind = Tok.getKind();
unsigned Arity = TypeTraitArity(Kind);
SourceLocation Loc = ConsumeToken();
BalancedDelimiterTracker Parens(*this, tok::l_paren);
if (Parens.expectAndConsume())
return ExprError();
SmallVector<ParsedType, 2> Args;
do {
TypeResult Ty = ParseTypeName();
if (Ty.isInvalid()) {
Parens.skipToEnd();
return ExprError();
}
if (Tok.is(tok::ellipsis)) {
Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken());
if (Ty.isInvalid()) {
Parens.skipToEnd();
return ExprError();
}
}
Args.push_back(Ty.get());
} while (TryConsumeToken(tok::comma));
if (Parens.consumeClose())
return ExprError();
SourceLocation EndLoc = Parens.getCloseLocation();
if (Arity && Args.size() != Arity) {
Diag(EndLoc, diag::err_type_trait_arity)
<< Arity << 0 << (Arity > 1) << (int)Args.size() << SourceRange(Loc);
return ExprError();
}
if (!Arity && Args.empty()) {
Diag(EndLoc, diag::err_type_trait_arity)
<< 1 << 1 << 1 << (int)Args.size() << SourceRange(Loc);
return ExprError();
}
return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc);
}
ExprResult Parser::ParseArrayTypeTrait() {
ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume())
return ExprError();
TypeResult Ty = ParseTypeName();
if (Ty.isInvalid()) {
SkipUntil(tok::comma, StopAtSemi);
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
switch (ATT) {
case ATT_ArrayRank: {
T.consumeClose();
return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), nullptr,
T.getCloseLocation());
}
case ATT_ArrayExtent: {
if (ExpectAndConsume(tok::comma)) {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
ExprResult DimExpr = ParseExpression();
T.consumeClose();
return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(),
T.getCloseLocation());
}
}
llvm_unreachable("Invalid ArrayTypeTrait!");
}
ExprResult Parser::ParseExpressionTrait() {
ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume())
return ExprError();
ExprResult Expr = ParseExpression();
T.consumeClose();
return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(),
T.getCloseLocation());
}
ExprResult
Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParsedType &CastTy,
BalancedDelimiterTracker &Tracker,
ColonProtectionRAIIObject &ColonProt) {
assert(getLangOpts().CPlusPlus && "Should only be called for C++!");
assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
assert(isTypeIdInParens() && "Not a type-id!");
ExprResult Result(true);
CastTy = nullptr;
ParenParseOption ParseAs;
CachedTokens Toks;
if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) {
Tracker.consumeClose();
return ExprError();
}
if (Tok.is(tok::l_brace)) {
ParseAs = CompoundLiteral;
} else {
bool NotCastExpr;
if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) {
NotCastExpr = true;
} else {
ColonProt.restore();
Result = ParseCastExpression(AnyCastExpr,
false,
NotCastExpr,
IsTypeCast);
}
ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
}
Token AttrEnd;
AttrEnd.startToken();
AttrEnd.setKind(tok::eof);
AttrEnd.setLocation(Tok.getLocation());
AttrEnd.setEofData(Toks.data());
Toks.push_back(AttrEnd);
Toks.push_back(Tok);
PP.EnterTokenStream(Toks, true,
true);
ConsumeAnyToken();
if (ParseAs >= CompoundLiteral) {
DeclSpec DS(AttrFactory);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
{
ColonProtectionRAIIObject InnerColonProtection(*this);
ParseSpecifierQualifierList(DS);
ParseDeclarator(DeclaratorInfo);
}
Tracker.consumeClose();
ColonProt.restore();
assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData());
ConsumeAnyToken();
if (ParseAs == CompoundLiteral) {
ExprType = CompoundLiteral;
if (DeclaratorInfo.isInvalidType())
return ExprError();
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
return ParseCompoundLiteralExpression(Ty.get(),
Tracker.getOpenLocation(),
Tracker.getCloseLocation());
}
assert(ParseAs == CastExpr);
if (DeclaratorInfo.isInvalidType())
return ExprError();
if (!Result.isInvalid())
Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(),
DeclaratorInfo, CastTy,
Tracker.getCloseLocation(), Result.get());
return Result;
}
assert(ParseAs == SimpleExpr);
ExprType = SimpleExpr;
Result = ParseExpression();
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(),
Tok.getLocation(), Result.get());
if (Result.isInvalid()) {
while (Tok.isNot(tok::eof))
ConsumeAnyToken();
assert(Tok.getEofData() == AttrEnd.getEofData());
ConsumeAnyToken();
return ExprError();
}
Tracker.consumeClose();
assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData());
ConsumeAnyToken();
return Result;
}
ExprResult Parser::ParseBuiltinBitCast() {
SourceLocation KWLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, "__builtin_bit_cast"))
return ExprError();
DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
ParseDeclarator(DeclaratorInfo);
if (ExpectAndConsume(tok::comma)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::comma;
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
ExprResult Operand = ParseExpression();
if (T.consumeClose())
return ExprError();
if (Operand.isInvalid() || DeclaratorInfo.isInvalidType())
return ExprError();
return Actions.ActOnBuiltinBitCastExpr(KWLoc, DeclaratorInfo, Operand,
T.getCloseLocation());
}