diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-02-15 00:27:53 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-02-15 00:27:53 +0000 |
commit | d1f4353f6e59e74948fb8442a8fda9b0bf379700 (patch) | |
tree | 757834eaede0e8913ca27f0c43fd1c8de7d3f2be /lib/Sema/SemaExpr.cpp | |
parent | 7ff8f050d264a0ed5d52063d500216eb36021fe5 (diff) | |
download | clang-d1f4353f6e59e74948fb8442a8fda9b0bf379700.tar.gz |
PR40642: Fix determination of whether the final statement of a statement
expression is a discarded-value expression.
Summary:
We used to get this wrong in three ways:
1) During parsing, an expression-statement followed by the }) ending a
statement expression was always treated as producing the value of the
statement expression. That's wrong for ({ if (1) expr; })
2) During template instantiation, various kinds of statement (most
statements not appearing directly in a compound-statement) were not
treated as discarded-value expressions, resulting in missing volatile
loads (etc).
3) In all contexts, an expression-statement with attributes was not
treated as producing the value of the statement expression, eg
({ [[attr]] expr; }).
Also fix incorrect enforcement of OpenMP rule that directives can "only
be placed in the program at a position where ignoring or deleting the
directive would result in a program with correct syntax". In particular,
a label (be it goto, case, or default) should not affect whether
directives are permitted.
Reviewers: aaron.ballman, rjmccall
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D57984
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@354090 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 107 |
1 files changed, 35 insertions, 72 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b992f3387e..00b4cddc6b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13301,29 +13301,6 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, Context.getPointerType(Context.VoidTy)); } -/// Given the last statement in a statement-expression, check whether -/// the result is a producing expression (like a call to an -/// ns_returns_retained function) and, if so, rebuild it to hoist the -/// release out of the full-expression. Otherwise, return null. -/// Cannot fail. -static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) { - // Should always be wrapped with one of these. - ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement); - if (!cleanups) return nullptr; - - ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr()); - if (!cast || cast->getCastKind() != CK_ARCConsumeObject) - return nullptr; - - // Splice out the cast. This shouldn't modify any interesting - // features of the statement. - Expr *producer = cast->getSubExpr(); - assert(producer->getType() == cast->getType()); - assert(producer->getValueKind() == cast->getValueKind()); - cleanups->setSubExpr(producer); - return cleanups; -} - void Sema::ActOnStartStmtExpr() { PushExpressionEvaluationContext(ExprEvalContexts.back().Context); } @@ -13357,47 +13334,10 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, QualType Ty = Context.VoidTy; bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { - Stmt *LastStmt = Compound->body_back(); - LabelStmt *LastLabelStmt = nullptr; - // If LastStmt is a label, skip down through into the body. - while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) { - LastLabelStmt = Label; - LastStmt = Label->getSubStmt(); - } - - if (Expr *LastE = dyn_cast<Expr>(LastStmt)) { - // Do function/array conversion on the last expression, but not - // lvalue-to-rvalue. However, initialize an unqualified type. - ExprResult LastExpr = DefaultFunctionArrayConversion(LastE); - if (LastExpr.isInvalid()) - return ExprError(); - Ty = LastExpr.get()->getType().getUnqualifiedType(); - - if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) { - // In ARC, if the final expression ends in a consume, splice - // the consume out and bind it later. In the alternate case - // (when dealing with a retainable type), the result - // initialization will create a produce. In both cases the - // result will be +1, and we'll need to balance that out with - // a bind. - if (Expr *rebuiltLastStmt - = maybeRebuildARCConsumingStmt(LastExpr.get())) { - LastExpr = rebuiltLastStmt; - } else { - LastExpr = PerformCopyInitialization( - InitializedEntity::InitializeStmtExprResult(LPLoc, Ty), - SourceLocation(), LastExpr); - } - - if (LastExpr.isInvalid()) - return ExprError(); - if (LastExpr.get() != nullptr) { - if (!LastLabelStmt) - Compound->setLastStmt(LastExpr.get()); - else - LastLabelStmt->setSubStmt(LastExpr.get()); - StmtExprMayBindToTemp = true; - } + if (const auto *LastStmt = dyn_cast<ValueStmt>(Compound->body_back())) { + if (const Expr *Value = LastStmt->getExprStmt()) { + StmtExprMayBindToTemp = true; + Ty = Value->getType(); } } } @@ -13410,6 +13350,37 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, return ResStmtExpr; } +ExprResult Sema::ActOnStmtExprResult(ExprResult ER) { + if (ER.isInvalid()) + return ExprError(); + + // Do function/array conversion on the last expression, but not + // lvalue-to-rvalue. However, initialize an unqualified type. + ER = DefaultFunctionArrayConversion(ER.get()); + if (ER.isInvalid()) + return ExprError(); + Expr *E = ER.get(); + + if (E->isTypeDependent()) + return E; + + // In ARC, if the final expression ends in a consume, splice + // the consume out and bind it later. In the alternate case + // (when dealing with a retainable type), the result + // initialization will create a produce. In both cases the + // result will be +1, and we'll need to balance that out with + // a bind. + auto *Cast = dyn_cast<ImplicitCastExpr>(E); + if (Cast && Cast->getCastKind() == CK_ARCConsumeObject) + return Cast->getSubExpr(); + + // FIXME: Provide a better location for the initialization. + return PerformCopyInitialization( + InitializedEntity::InitializeStmtExprResult( + E->getBeginLoc(), E->getType().getUnqualifiedType()), + SourceLocation(), E); +} + ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef<OffsetOfComponent> Components, @@ -14490,14 +14461,6 @@ namespace { // Make sure we redo semantic analysis bool AlwaysRebuild() { return true; } - // Make sure we handle LabelStmts correctly. - // FIXME: This does the right thing, but maybe we need a more general - // fix to TreeTransform? - StmtResult TransformLabelStmt(LabelStmt *S) { - S->getDecl()->setStmt(nullptr); - return BaseTransform::TransformLabelStmt(S); - } - // We need to special-case DeclRefExprs referring to FieldDecls which // are not part of a member pointer formation; normal TreeTransforming // doesn't catch this case because of the way we represent them in the AST. |