/// parsed.
class CompoundScopeInfo {
public:
- CompoundScopeInfo()
- : HasEmptyLoopBodies(false) { }
+ CompoundScopeInfo(bool IsStmtExpr)
+ : HasEmptyLoopBodies(false), IsStmtExpr(IsStmtExpr) { }
/// \brief Whether this compound stamement contains `for' or `while' loops
/// with empty bodies.
bool HasEmptyLoopBodies;
+ /// \brief Whether this compound statement corresponds to a GNU statement
+ /// expression.
+ bool IsStmtExpr;
+
void setHasEmptyLoopBodies() {
HasEmptyLoopBodies = true;
}
getCurFunction()->recordUseOfWeak(E, IsRead);
}
- void PushCompoundScope();
+ void PushCompoundScope(bool IsStmtExpr);
void PopCompoundScope();
sema::CompoundScopeInfo &getCurCompoundScope() const;
StmtResult ActOnNullStmt(SourceLocation SemiLoc,
bool HasLeadingEmptyMacro = false);
- void ActOnStartOfCompoundStmt();
+ void ActOnStartOfCompoundStmt(bool IsStmtExpr);
void ActOnFinishOfCompoundStmt();
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr);
/// \brief A RAII object to enter scope of a compound statement.
class CompoundScopeRAII {
public:
- CompoundScopeRAII(Sema &S): S(S) {
- S.ActOnStartOfCompoundStmt();
+ CompoundScopeRAII(Sema &S, bool IsStmtExpr = false) : S(S) {
+ S.ActOnStartOfCompoundStmt(IsStmtExpr);
}
~CompoundScopeRAII() {
StmtResult AssociatedStmt;
if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
- Sema::CompoundScopeRAII CompoundScope(Actions);
Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
- Actions.ActOnStartOfCompoundStmt();
- // Parse statement
- AssociatedStmt = ParseStatement();
- Actions.ActOnFinishOfCompoundStmt();
+ // FIXME: We create a bogus CompoundStmt scope to hold the contents of
+ // the captured region. Code elsewhere assumes that any FunctionScopeInfo
+ // should have at least one compound statement scope within it.
+ AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement());
AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
} else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||
DKind == OMPD_target_exit_data) {
- Sema::CompoundScopeRAII CompoundScope(Actions);
Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
- Actions.ActOnStartOfCompoundStmt();
- AssociatedStmt =
- Actions.ActOnCompoundStmt(Loc, Loc, llvm::None, /*isStmtExpr=*/false);
- Actions.ActOnFinishOfCompoundStmt();
+ AssociatedStmt = (Sema::CompoundScopeRAII(Actions),
+ Actions.ActOnCompoundStmt(Loc, Loc, llvm::None,
+ /*isStmtExpr=*/false));
AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
}
Directive = Actions.ActOnOpenMPExecutableDirective(
if (T.consumeOpen())
return StmtError();
- Sema::CompoundScopeRAII CompoundScope(Actions);
+ Sema::CompoundScopeRAII CompoundScope(Actions, isStmtExpr);
// Parse any pragmas at the beginning of the compound statement.
ParseCompoundStatementLeadingPragmas();
delete Scope;
}
-void Sema::PushCompoundScope() {
- getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo());
+void Sema::PushCompoundScope(bool IsStmtExpr) {
+ getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo(IsStmtExpr));
}
void Sema::PopCompoundScope() {
DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2);
}
-void Sema::ActOnStartOfCompoundStmt() {
- PushCompoundScope();
+void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
+ PushCompoundScope(IsStmtExpr);
}
void Sema::ActOnFinishOfCompoundStmt() {
// later.
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
for (unsigned N = FunctionScopes.size(); N; --N) {
- if (sema::LambdaScopeInfo *LSI =
- dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
+ sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
+ // We do not permit pack expansion that would duplicate a statement
+ // expression, not even within a lambda.
+ // FIXME: We could probably support this for statement expressions that do
+ // not contain labels, and for pack expansions that expand both the stmt
+ // expr and the enclosing lambda.
+ if (std::any_of(
+ Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
+ [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; }))
+ break;
+
+ if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
if (N == FunctionScopes.size()) {
for (auto &Param : Unexpanded) {
auto *PD = dyn_cast_or_null<ParmVarDecl>(
--- /dev/null
+// RUN: %clang_cc1 -verify %s
+
+// FIXME: We could in principle support cases like this (particularly, cases
+// where the statement-expression contains no labels).
+template <typename... T> void f1() {
+ int arr[] = {
+ ({
+ T(); // expected-error {{unexpanded parameter pack}}
+ }) ... // expected-error {{does not contain any unexpanded parameter packs}}
+ };
+}
+
+// FIXME: The error for this isn't ideal; it'd be preferable to say that pack
+// expansion of a statement expression is not permitted.
+template <typename... T> void f2() {
+ [] {
+ int arr[] = {
+ T() + ({
+ foo:
+ T t; // expected-error {{unexpanded parameter pack}}
+ goto foo;
+ 0;
+ }) ...
+ };
+ };
+}
+
+template <typename... T> void f3() {
+ ({
+ int arr[] = {
+ [] {
+ foo:
+ T t; // OK, expanded within compound statement
+ goto foo;
+ return 0;
+ } ...
+ };
+ });
+}