diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Sema/ScopeInfo.h | 8 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 8 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 14 | ||||
-rw-r--r-- | clang/test/SemaTemplate/stmt-expr.cpp | 39 |
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; + } ... + }; + }); +} |