Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ def select_constexpr_spec_kind : TextSubstitution<
def fatal_too_many_errors
: Error<"too many errors emitted, stopping now">, DefaultFatal;

// TODO: Remove this.
def err_expansion_statements_todo : Error<
"TODO (expansion statements)">;

def warn_stack_exhausted : Warning<
"stack nearly exhausted; compilation time may suffer, and "
"crashes due to stack overflow are likely">,
Expand Down
17 changes: 15 additions & 2 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ let CategoryName = "Parse Issue" in {
defm enum_fixed_underlying_type : CXX11Compat<
"enumeration types with a fixed underlying type are",
/*ext_warn=*/false>;

// C++26 compatibility with C++23.
defm expansion_statements : CXX26Compat<
"expansion statements are">;
}

def err_asm_qualifier_ignored : Error<
Expand Down Expand Up @@ -419,9 +423,10 @@ def warn_cxx98_compat_for_range : Warning<
"range-based for loop is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_for_range_identifier : Error<
"range-based for loop requires type for loop variable">;
"%select{range-based for loop|expansion statement}0 requires "
"type for %select{loop|expansion}0 variable">;
def err_for_range_expected_decl : Error<
"for range declaration must declare a variable">;
"%select{for range|expansion statement}0 declaration must declare a variable">;
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;
Expand All @@ -448,6 +453,14 @@ def err_unspecified_size_with_static : Error<
"'static' may not be used without an array size">;
def err_expected_parentheses_around_typename : Error<
"expected parentheses around type name in %0 expression">;
def err_expansion_stmt_requires_range : Error<
"expansion statement must be a range-based for loop">;
def err_expansion_stmt_requires_cxx2c : Error<
"expansion statements are only supported in C++2c">;
def err_for_template : Error<
"'for template' is invalid; use 'template for' instead">;
def err_expansion_stmt_invalid_kw : Error<
"'template %0' is invalid">;

def err_expected_case_before_expression: Error<
"expected 'case' keyword before expression">;
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2900,10 +2900,10 @@ def note_which_delegates_to : Note<"which delegates to">;

// C++11 range-based for loop
def err_for_range_decl_must_be_var : Error<
"for range declaration must declare a variable">;
"%select{for range|expansion statement}0 declaration must declare a variable">;
def err_for_range_storage_class : Error<
"loop variable %0 may not be declared %select{'extern'|'static'|"
"'__private_extern__'|'auto'|'register'|'constexpr'|'thread_local'}1">;
"%select{loop|expansion}0 variable %1 may not be declared %select{'extern'|'static'|"
"'__private_extern__'|'auto'|'register'|'constexpr'|'thread_local'}2">;
def err_type_defined_in_for_range : Error<
"types may not be defined in a for range declaration">;
def err_for_range_deduction_failure : Error<
Expand Down
42 changes: 38 additions & 4 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1700,11 +1700,13 @@ class Parser : public CodeCompletionHandler {
}

/// Information on a C++0x for-range-initializer found while parsing a
/// declaration which turns out to be a for-range-declaration.
/// declaration which turns out to be a for-range-declaration. Also used
/// for C++26's expansion statements.
struct ForRangeInit {
SourceLocation ColonLoc;
ExprResult RangeExpr;
SmallVector<MaterializeTemporaryExpr *, 8> LifetimeExtendTemps;
bool ExpansionStmt = false;
bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
};
struct ForRangeInfo : ForRangeInit {
Expand Down Expand Up @@ -4186,7 +4188,8 @@ class Parser : public CodeCompletionHandler {
bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
llvm::function_ref<void()> ExpressionStarts =
llvm::function_ref<void()>(),
bool FailImmediatelyOnInvalidExpr = false);
bool FailImmediatelyOnInvalidExpr = false,
bool ParsingExpansionInitList = false);

/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
/// used for misc language extensions.
Expand Down Expand Up @@ -5246,6 +5249,16 @@ class Parser : public CodeCompletionHandler {
///
ExprResult ParseBraceInitializer();

/// ParseExpansionInitList - Called when the initializer of an expansion
/// statement starts with an open brace.
///
/// \verbatim
/// expansion-init-list: [C++26 [stmt.expand]]
/// '{' expression-list ','[opt] '}'
/// '{' '}'
/// \endverbatim
ExprResult ParseExpansionInitList();

struct DesignatorCompletionInfo {
SmallVectorImpl<Expr *> &InitExprs;
QualType PreferredBaseType;
Expand Down Expand Up @@ -7452,8 +7465,12 @@ class Parser : public CodeCompletionHandler {
/// [C++0x] expression
/// [C++0x] braced-init-list [TODO]
/// \endverbatim
StmtResult ParseForStatement(SourceLocation *TrailingElseLoc,
LabelDecl *PrecedingLabel);
StmtResult ParseForStatement(
SourceLocation *TrailingElseLoc, LabelDecl *PrecedingLabel,
CXXExpansionStmtDecl *CXXExpansionStmtDeclaration = nullptr);

void ParseForRangeInitializerAfterColon(ForRangeInit &FRI,
ParsingDeclSpec *VarDeclSpec);

/// ParseGotoStatement
/// \verbatim
Expand Down Expand Up @@ -7500,6 +7517,23 @@ class Parser : public CodeCompletionHandler {

StmtResult ParseBreakOrContinueStatement(bool IsContinue);

/// ParseExpansionStatement - Parse a C++26 expansion
/// statement ('template for').
///
/// \verbatim
/// expansion-statement:
/// 'template' 'for' '(' init-statement[opt]
/// for-range-declaration ':' expansion-initializer ')'
/// compound-statement
///
/// expansion-initializer:
/// expression
/// expansion-init-list
/// \endverbatim
StmtResult ParseExpansionStatement(SourceLocation *TrailingElseLoc,
LabelDecl *PrecedingLabel,
SourceLocation TemplateLoc);

StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx,
SourceLocation *TrailingElseLoc,
ParsedAttributes &Attrs,
Expand Down
33 changes: 32 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,7 @@ class Sema final : public SemaBase {
// 33. Types (SemaType.cpp)
// 34. FixIt Helpers (SemaFixItUtils.cpp)
// 35. Function Effects (SemaFunctionEffects.cpp)
// 36. C++ Expansion Statements (SemaExpand.cpp)

/// \name Semantic Analysis
/// Implementations are in Sema.cpp
Expand Down Expand Up @@ -4097,7 +4098,7 @@ class Sema final : public SemaBase {
/// complete.
void ActOnInitializerError(Decl *Dcl);

void ActOnCXXForRangeDecl(Decl *D);
void ActOnCXXForRangeDecl(Decl *D, bool InExpansionStmt);
StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
ParsedAttributes &Attrs);
Expand Down Expand Up @@ -15613,6 +15614,36 @@ class Sema final : public SemaBase {
void performFunctionEffectAnalysis(TranslationUnitDecl *TU);

///@}

//
//
// -------------------------------------------------------------------------
//
//

/// \name Expansion Statements
/// Implementations are in SemaExpand.cpp
///@{
public:
CXXExpansionStmtDecl *ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
SourceLocation TemplateKWLoc);

CXXExpansionStmtDecl *
BuildCXXExpansionStmtDecl(DeclContext *Ctx, SourceLocation TemplateKWLoc,
NonTypeTemplateParmDecl *NTTP);

ExprResult ActOnCXXExpansionInitList(MultiExprArg SubExprs,
SourceLocation LBraceLoc,
SourceLocation RBraceLoc);

StmtResult ActOnCXXExpansionStmtPattern(
CXXExpansionStmtDecl *ESD, Stmt *Init, Stmt *ExpansionVarStmt,
Expr *ExpansionInitializer, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation RParenLoc,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps);

StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
///@}
};

DeductionFailureInfo
Expand Down
37 changes: 6 additions & 31 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2304,43 +2304,18 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Handle the Objective-C for-in loop variable similarly, although we
// don't need to parse the container in advance.
if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) {
bool IsForRangeLoop = false;
bool IsForRangeLoopOrExpansionStmt = false;
if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
IsForRangeLoop = true;
EnterExpressionEvaluationContext ForRangeInitContext(
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
/*LambdaContextDecl=*/nullptr,
Sema::ExpressionEvaluationContextRecord::EK_Other,
getLangOpts().CPlusPlus23);

// P2718R0 - Lifetime extension in range-based for loops.
if (getLangOpts().CPlusPlus23) {
auto &LastRecord = Actions.currentEvaluationContext();
LastRecord.InLifetimeExtendingContext = true;
LastRecord.RebuildDefaultArgOrDefaultInit = true;
}

if (getLangOpts().OpenMP)
IsForRangeLoopOrExpansionStmt = true;
if (getLangOpts().OpenMP && !FRI->ExpansionStmt)
Actions.OpenMP().startOpenMPCXXRangeFor();
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else
FRI->RangeExpr = ParseExpression();

// Before c++23, ForRangeLifetimeExtendTemps should be empty.
assert(
getLangOpts().CPlusPlus23 ||
Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps.empty());

// Move the collected materialized temporaries into ForRangeInit before
// ForRangeInitContext exit.
FRI->LifetimeExtendTemps = std::move(
Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps);
ParseForRangeInitializerAfterColon(*FRI, &DS);
}

Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
if (IsForRangeLoop) {
Actions.ActOnCXXForRangeDecl(ThisDecl);
if (IsForRangeLoopOrExpansionStmt) {
Actions.ActOnCXXForRangeDecl(ThisDecl, FRI->ExpansionStmt);
} else {
// Obj-C for loop
if (auto *VD = dyn_cast_or_null<VarDecl>(ThisDecl))
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3166,7 +3166,8 @@ void Parser::injectEmbedTokens() {

bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
llvm::function_ref<void()> ExpressionStarts,
bool FailImmediatelyOnInvalidExpr) {
bool FailImmediatelyOnInvalidExpr,
bool ParsingExpansionInitList) {
bool SawError = false;
while (true) {
if (ExpressionStarts)
Expand Down Expand Up @@ -3195,7 +3196,11 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
SawError = true;
if (FailImmediatelyOnInvalidExpr)
break;
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);

// We expect '}' rather than ')' at the end of an expansion-init-list.
SkipUntil(tok::comma,
ParsingExpansionInitList ? tok::r_brace : tok::r_paren,
StopAtSemi | StopBeforeMatch);
} else {
Exprs.push_back(Expr.get());
}
Expand All @@ -3205,6 +3210,11 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
// Move to the next argument, remember where the comma was.
Token Comma = Tok;
ConsumeToken();

// CWG 3061: Trailing commas are allowed in expansion-init-lists.
if (ParsingExpansionInitList && Tok.is(tok::r_brace))
break;

checkPotentialAngleBracketDelimiter(Comma);
}
return SawError;
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Parse/ParseInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,25 @@ ExprResult Parser::ParseBraceInitializer() {
return ExprError(); // an error occurred.
}

ExprResult Parser::ParseExpansionInitList() {
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();

ExprVector InitExprs;

if (!Tok.is(tok::r_brace) &&
ParseExpressionList(InitExprs, /*ExpressionStarts=*/{},
/*FailImmediatelyOnInvalidExpr=*/false,
/*ParsingExpansionInitList=*/true)) {
T.consumeClose();
return ExprError();
}

T.consumeClose();
return Actions.ActOnCXXExpansionInitList(InitExprs, T.getOpenLocation(),
T.getCloseLocation());
}

bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
bool &InitExprsOk) {
bool trailingComma = false;
Expand Down
Loading
Loading