summaryrefslogtreecommitdiff
path: root/lib/Parse/ParseExprCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseExprCXX.cpp')
-rw-r--r--lib/Parse/ParseExprCXX.cpp215
1 files changed, 154 insertions, 61 deletions
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index f8938ba3495b..b09d7dbc12fc 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -283,8 +283,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
//
// To implement this, we clear out the object type as soon as we've
// seen a leading '::' or part of a nested-name-specifier.
- ObjectType = ParsedType();
-
+ ObjectType = nullptr;
+
if (Tok.is(tok::code_completion)) {
// Code completion for a nested-name-specifier, where the code
// code completion token follows the '::'.
@@ -597,7 +597,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe
/*EnteringContext=*/false,
/*AllowDestructorName=*/false,
/*AllowConstructorName=*/false,
- /*ObjectType=*/ParsedType(), TemplateKWLoc, Name))
+ /*ObjectType=*/nullptr, TemplateKWLoc, Name))
return ExprError();
// This is only the direct operand of an & operator if it is not
@@ -659,7 +659,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// '::' unqualified-id
//
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
Token Replacement;
ExprResult Result =
@@ -739,8 +739,11 @@ ExprResult Parser::TryParseLambdaExpression() {
&& Tok.is(tok::l_square)
&& "Not at the start of a possible lambda expression.");
- const Token Next = NextToken(), After = GetLookAheadToken(2);
+ const Token Next = NextToken();
+ if (Next.is(tok::eof)) // Nothing else to lookup here...
+ return ExprEmpty();
+ const Token After = GetLookAheadToken(2);
// If lookahead indicates this is a lambda...
if (Next.is(tok::r_square) || // []
Next.is(tok::equal) || // [=
@@ -846,8 +849,16 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
IdentifierInfo *Id = nullptr;
SourceLocation EllipsisLoc;
ExprResult Init;
-
- if (Tok.is(tok::kw_this)) {
+
+ if (Tok.is(tok::star)) {
+ Loc = ConsumeToken();
+ if (Tok.is(tok::kw_this)) {
+ ConsumeToken();
+ Kind = LCK_StarThis;
+ } else {
+ return DiagResult(diag::err_expected_star_this_capture);
+ }
+ } else if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
Loc = ConsumeToken();
} else {
@@ -1042,6 +1053,58 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
return false;
}
+static void
+tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc,
+ SourceLocation &ConstexprLoc,
+ SourceLocation &DeclEndLoc) {
+ assert(MutableLoc.isInvalid());
+ assert(ConstexprLoc.isInvalid());
+ // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc
+ // to the final of those locations. Emit an error if we have multiple
+ // copies of those keywords and recover.
+
+ 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 /*switch*/;
+ }
+ 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 /*switch*/;
+ default:
+ return;
+ }
+ }
+}
+
+static void
+addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
+ DeclSpec &DS) {
+ if (ConstexprLoc.isValid()) {
+ P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus1z
+ ? diag::ext_constexpr_on_lambda_cxx1z
+ : diag::warn_cxx14_compat_constexpr_on_lambda);
+ const char *PrevSpec = nullptr;
+ unsigned DiagID = 0;
+ DS.SetConstexprSpec(ConstexprLoc, PrevSpec, DiagID);
+ assert(PrevSpec == nullptr && DiagID == 0 &&
+ "Constexpr cannot have been set previously!");
+ }
+}
+
/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
@@ -1100,10 +1163,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// compatible with MSVC.
MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc);
- // Parse 'mutable'[opt].
+ // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc.
SourceLocation MutableLoc;
- if (TryConsumeToken(tok::kw_mutable, MutableLoc))
- DeclEndLoc = MutableLoc;
+ SourceLocation ConstexprLoc;
+ tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc,
+ DeclEndLoc);
+
+ addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
// Parse exception-specification[opt].
ExceptionSpecificationType ESpecType = EST_None;
@@ -1161,7 +1227,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType),
Attr, DeclEndLoc);
- } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute) ||
+ } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
+ tok::kw_constexpr) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
// It's common to forget that one needs '()' before 'mutable', an attribute
// specifier, or the result type. Deal with this.
@@ -1171,6 +1238,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
case tok::arrow: TokKind = 1; break;
case tok::kw___attribute:
case tok::l_square: TokKind = 2; break;
+ case tok::kw_constexpr: TokKind = 3; break;
default: llvm_unreachable("Unknown token kind");
}
@@ -1658,46 +1726,58 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
-/// \param ExprOut if the condition was parsed as an expression, the parsed
-/// expression.
+/// In C++1z, a condition may in some contexts be preceded by an
+/// optional init-statement. This function will parse that too.
///
-/// \param DeclOut if the condition was parsed as a declaration, the parsed
-/// declaration.
+/// \param InitStmt If non-null, an init-statement is permitted, and if present
+/// will be parsed and stored here.
///
/// \param Loc The location of the start of the statement that requires this
/// condition, e.g., the "for" in a for loop.
///
-/// \param ConvertToBoolean Whether the condition expression should be
-/// converted to a boolean value.
-///
-/// \returns true if there was a parsing, false otherwise.
-bool Parser::ParseCXXCondition(ExprResult &ExprOut,
- Decl *&DeclOut,
- SourceLocation Loc,
- bool ConvertToBoolean) {
+/// \returns The parsed condition.
+Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
+ SourceLocation Loc,
+ Sema::ConditionKind CK) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
cutOffParsing();
- return true;
+ return Sema::ConditionError();
}
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
- if (!isCXXConditionDeclaration()) {
+ // Determine what kind of thing we have.
+ switch (isCXXConditionDeclarationOrInitStatement(InitStmt)) {
+ case ConditionOrInitStatement::Expression: {
ProhibitAttributes(attrs);
// Parse the expression.
- ExprOut = ParseExpression(); // expression
- DeclOut = nullptr;
- if (ExprOut.isInvalid())
- return true;
+ ExprResult Expr = ParseExpression(); // expression
+ if (Expr.isInvalid())
+ return Sema::ConditionError();
+
+ if (InitStmt && Tok.is(tok::semi)) {
+ *InitStmt = Actions.ActOnExprStmt(Expr.get());
+ ConsumeToken();
+ return ParseCXXCondition(nullptr, Loc, CK);
+ }
+
+ return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK);
+ }
+
+ case ConditionOrInitStatement::InitStmtDecl: {
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(
+ Declarator::InitStmtContext, DeclEnd, attrs, /*RequireSemi=*/true);
+ *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
+ return ParseCXXCondition(nullptr, Loc, CK);
+ }
- // If required, convert to a boolean value.
- if (ConvertToBoolean)
- ExprOut
- = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprOut.get());
- return ExprOut.isInvalid();
+ case ConditionOrInitStatement::ConditionDecl:
+ case ConditionOrInitStatement::Error:
+ break;
}
// type-specifier-seq
@@ -1715,7 +1795,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopAtSemi);
- return true;
+ return Sema::ConditionError();
}
DeclaratorInfo.setAsmLabel(AsmLabel.get());
DeclaratorInfo.SetRangeEnd(Loc);
@@ -1727,8 +1807,9 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// Type-check the declaration itself.
DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(),
DeclaratorInfo);
- DeclOut = Dcl.get();
- ExprOut = ExprError();
+ if (Dcl.isInvalid())
+ return Sema::ConditionError();
+ Decl *DeclOut = Dcl.get();
// '=' assignment-expression
// If a '==' or '+=' is found, suggest a fixit to '='.
@@ -1748,12 +1829,11 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
SourceLocation LParen = ConsumeParen(), RParen = LParen;
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch))
RParen = ConsumeParen();
- Diag(DeclOut ? DeclOut->getLocation() : LParen,
+ Diag(DeclOut->getLocation(),
diag::err_expected_init_in_condition_lparen)
<< SourceRange(LParen, RParen);
} else {
- Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(),
- diag::err_expected_init_in_condition);
+ Diag(DeclOut->getLocation(), diag::err_expected_init_in_condition);
}
if (!InitExpr.isInvalid())
@@ -1762,12 +1842,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
else
Actions.ActOnInitializerError(DeclOut);
- // FIXME: Build a reference to this declaration? Convert it to bool?
- // (This is currently handled by Sema).
-
Actions.FinalizeDeclaration(DeclOut);
-
- return false;
+ return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
}
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
@@ -1863,6 +1939,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::kw_double:
DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy);
break;
+ case tok::kw___float128:
+ DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy);
+ break;
case tok::kw_wchar_t:
DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy);
break;
@@ -2413,9 +2492,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
// We have parsed a constructor name.
- ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(),
- &SS, false, false,
- ParsedType(),
+ ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, false,
+ false, nullptr,
/*IsCtorOrDtorName=*/true,
/*NonTrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, IdLoc, IdLoc);
@@ -2451,13 +2529,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
<< TemplateId->Name
<< FixItHint::CreateRemoval(
SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
- ParsedType Ty = Actions.getTypeName(*TemplateId->Name,
- TemplateId->TemplateNameLoc,
- getCurScope(),
- &SS, false, false,
- ParsedType(),
- /*IsCtorOrDtorName=*/true,
- /*NontrivialTypeSourceInfo=*/true);
+ ParsedType Ty =
+ Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc,
+ getCurScope(), &SS, false, false, nullptr,
+ /*IsCtorOrDtorName=*/true,
+ /*NontrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
ConsumeToken();
@@ -2541,7 +2617,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext))
return true;
if (SS.isNotEmpty())
- ObjectType = ParsedType();
+ ObjectType = nullptr;
if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) ||
!SS.isSet()) {
Diag(TildeLoc, diag::err_destructor_tilde_scope);
@@ -2563,7 +2639,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
SourceLocation ClassNameLoc = ConsumeToken();
if (TemplateSpecified || Tok.is(tok::less)) {
- Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc);
+ Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
ClassName, ClassNameLoc,
EnteringContext, ObjectType,
@@ -3029,7 +3105,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
assert(isTypeIdInParens() && "Not a type-id!");
ExprResult Result(true);
- CastTy = ParsedType();
+ CastTy = nullptr;
// We need to disambiguate a very ugly part of the C++ syntax:
//
@@ -3084,12 +3160,19 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
}
+ // Create a fake EOF to mark end of Toks buffer.
+ Token AttrEnd;
+ AttrEnd.startToken();
+ AttrEnd.setKind(tok::eof);
+ AttrEnd.setLocation(Tok.getLocation());
+ AttrEnd.setEofData(Toks.data());
+ Toks.push_back(AttrEnd);
+
// The current token should go after the cached tokens.
Toks.push_back(Tok);
// Re-enter the stored parenthesized tokens into the token stream, so we may
// parse them now.
- PP.EnterTokenStream(Toks.data(), Toks.size(),
- true/*DisableMacroExpansion*/, false/*OwnsTokens*/);
+ PP.EnterTokenStream(Toks, true /*DisableMacroExpansion*/);
// Drop the current token and bring the first cached one. It's the same token
// as when we entered this function.
ConsumeAnyToken();
@@ -3108,6 +3191,10 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
Tracker.consumeClose();
ColonProt.restore();
+ // Consume EOF marker for Toks buffer.
+ assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData());
+ ConsumeAnyToken();
+
if (ParseAs == CompoundLiteral) {
ExprType = CompoundLiteral;
if (DeclaratorInfo.isInvalidType())
@@ -3144,10 +3231,16 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// Match the ')'.
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi);
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ assert(Tok.getEofData() == AttrEnd.getEofData());
+ ConsumeAnyToken();
return ExprError();
}
Tracker.consumeClose();
+ // Consume EOF marker for Toks buffer.
+ assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData());
+ ConsumeAnyToken();
return Result;
}