summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Sema/ScopeInfo.h8
-rw-r--r--clang/include/clang/Sema/Sema.h8
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp17
-rw-r--r--clang/lib/Parse/ParseStmt.cpp2
-rw-r--r--clang/lib/Sema/Sema.cpp4
-rw-r--r--clang/lib/Sema/SemaStmt.cpp4
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp14
-rw-r--r--clang/test/SemaTemplate/stmt-expr.cpp39
8 files changed, 73 insertions, 23 deletions
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 3aa34ae0e01..5f96f595631 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -55,13 +55,17 @@ namespace sema {
/// 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;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7349edff617..2614a64d4ac 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1339,7 +1339,7 @@ public:
getCurFunction()->recordUseOfWeak(E, IsRead);
}
- void PushCompoundScope();
+ void PushCompoundScope(bool IsStmtExpr);
void PopCompoundScope();
sema::CompoundScopeInfo &getCurCompoundScope() const;
@@ -3667,7 +3667,7 @@ public:
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);
@@ -3675,8 +3675,8 @@ public:
/// \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() {
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index f3edf7ca51f..e9f2029fb70 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -1080,21 +1080,18 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
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(
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 09ae9d7f22f..b63c69db480 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -954,7 +954,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
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();
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index e07f60989d8..45fd2d3249d 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1393,8 +1393,8 @@ void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
delete Scope;
}
-void Sema::PushCompoundScope() {
- getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo());
+void Sema::PushCompoundScope(bool IsStmtExpr) {
+ getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo(IsStmtExpr));
}
void Sema::PopCompoundScope() {
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1ebc36716a8..93907038e05 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -337,8 +337,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2);
}
-void Sema::ActOnStartOfCompoundStmt() {
- PushCompoundScope();
+void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
+ PushCompoundScope(IsStmtExpr);
}
void Sema::ActOnFinishOfCompoundStmt() {
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index d81837dad50..7aa0e317df0 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -314,8 +314,18 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
// 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>(
diff --git a/clang/test/SemaTemplate/stmt-expr.cpp b/clang/test/SemaTemplate/stmt-expr.cpp
new file mode 100644
index 00000000000..2516a5220c1
--- /dev/null
+++ b/clang/test/SemaTemplate/stmt-expr.cpp
@@ -0,0 +1,39 @@
+// 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;
+ } ...
+ };
+ });
+}
OpenPOWER on IntegriCloud