Skip to content

Commit

Permalink
[Temporary] Add an ExprWithCleanups for each C++ MaterializeTemporary…
Browse files Browse the repository at this point in the history
…Expr.

These ExprWithCleanups are added for holding a RunCleanupsScope not
for destructor calls; rather, they are for lifetime marks. This requires
ExprWithCleanups to keep a bit to indicate whether it have cleanups with
side effects (e.g. dtor calls).

Differential Revision: http://reviews.llvm.org/D20498

llvm-svn: 272296
  • Loading branch information
timshen91 committed Jun 9, 2016
1 parent 17b4701 commit f120a7b
Show file tree
Hide file tree
Showing 23 changed files with 181 additions and 63 deletions.
7 changes: 6 additions & 1 deletion clang/include/clang/AST/ExprCXX.h
Expand Up @@ -2877,7 +2877,8 @@ class ExprWithCleanups final
Stmt *SubExpr;

ExprWithCleanups(EmptyShell, unsigned NumObjects);
ExprWithCleanups(Expr *SubExpr, ArrayRef<CleanupObject> Objects);
ExprWithCleanups(Expr *SubExpr, bool CleanupsHaveSideEffects,
ArrayRef<CleanupObject> Objects);

friend TrailingObjects;
friend class ASTStmtReader;
Expand All @@ -2887,6 +2888,7 @@ class ExprWithCleanups final
unsigned numObjects);

static ExprWithCleanups *Create(const ASTContext &C, Expr *subexpr,
bool CleanupsHaveSideEffects,
ArrayRef<CleanupObject> objects);

ArrayRef<CleanupObject> getObjects() const {
Expand All @@ -2903,6 +2905,9 @@ class ExprWithCleanups final

Expr *getSubExpr() { return cast<Expr>(SubExpr); }
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
bool cleanupsHaveSideEffects() const {
return ExprWithCleanupsBits.CleanupsHaveSideEffects;
}

/// As with any mutator of the AST, be very careful
/// when modifying an existing AST to preserve its invariants.
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/Stmt.h
Expand Up @@ -192,7 +192,10 @@ class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {

unsigned : NumExprBits;

unsigned NumObjects : 32 - NumExprBits;
// When false, it must not have side effects.
bool CleanupsHaveSideEffects : 1;

unsigned NumObjects : 32 - 1 - NumExprBits;
};

class PseudoObjectExprBitfields {
Expand Down
47 changes: 47 additions & 0 deletions clang/include/clang/Sema/CleanupInfo.h
@@ -0,0 +1,47 @@
//===--- CleanupInfo.cpp - Cleanup Control in Sema ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a set of operations on whether generating an
// ExprWithCleanups in a full expression.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_CLEANUP_INFO_H
#define LLVM_CLANG_SEMA_CLEANUP_INFO_H

namespace clang {

class CleanupInfo {
bool ExprNeedsCleanups = false;
bool CleanupsHaveSideEffects = false;

public:
bool exprNeedsCleanups() const { return ExprNeedsCleanups; }

bool cleanupsHaveSideEffects() const { return CleanupsHaveSideEffects; }

void setExprNeedsCleanups(bool SideEffects) {
ExprNeedsCleanups = true;
CleanupsHaveSideEffects |= SideEffects;
}

void reset() {
ExprNeedsCleanups = false;
CleanupsHaveSideEffects = false;
}

void mergeFrom(CleanupInfo Rhs) {
ExprNeedsCleanups |= Rhs.ExprNeedsCleanups;
CleanupsHaveSideEffects |= Rhs.CleanupsHaveSideEffects;
}
};

} // end namespace clang

#endif
5 changes: 3 additions & 2 deletions clang/include/clang/Sema/ScopeInfo.h
Expand Up @@ -19,6 +19,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CapturedStmt.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/CleanupInfo.h"
#include "clang/Sema/Ownership.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
Expand Down Expand Up @@ -682,7 +683,7 @@ class LambdaScopeInfo final : public CapturingScopeInfo {
bool ExplicitParams;

/// \brief Whether any of the capture expressions requires cleanups.
bool ExprNeedsCleanups;
CleanupInfo Cleanup;

/// \brief Whether the lambda contains an unexpanded parameter pack.
bool ContainsUnexpandedParameterPack;
Expand Down Expand Up @@ -730,7 +731,7 @@ class LambdaScopeInfo final : public CapturingScopeInfo {
LambdaScopeInfo(DiagnosticsEngine &Diag)
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr),
CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false),
ExplicitParams(false), ExprNeedsCleanups(false),
ExplicitParams(false), Cleanup{},
ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0),
GLTemplateParameterList(nullptr) {
Kind = SK_Lambda;
Expand Down
16 changes: 10 additions & 6 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -34,6 +34,7 @@
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/Sema/CleanupInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/IdentifierResolver.h"
Expand Down Expand Up @@ -440,9 +441,8 @@ class Sema {
/// if Sema is already doing so, which would cause infinite recursions.
bool IsBuildingRecoveryCallExpr;

/// ExprNeedsCleanups - True if the current evaluation context
/// requires cleanups to be run at its conclusion.
bool ExprNeedsCleanups;
/// Used to control the generation of ExprWithCleanups.
CleanupInfo Cleanup;

/// ExprCleanupObjects - This is the stack of objects requiring
/// cleanup that are created by the current full expression. The
Expand Down Expand Up @@ -830,7 +830,7 @@ class Sema {
ExpressionEvaluationContext Context;

/// \brief Whether the enclosing context needed a cleanup.
bool ParentNeedsCleanups;
CleanupInfo ParentCleanup;

/// \brief Whether we are in a decltype expression.
bool IsDecltype;
Expand Down Expand Up @@ -871,10 +871,10 @@ class Sema {

ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
bool ParentNeedsCleanups,
CleanupInfo ParentCleanup,
Decl *ManglingContextDecl,
bool IsDecltype)
: Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
: Context(Context), ParentCleanup(ParentCleanup),
IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects),
NumTypos(0),
ManglingContextDecl(ManglingContextDecl), MangleNumbering() { }
Expand Down Expand Up @@ -4872,6 +4872,10 @@ class Sema {
Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt);
ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr);

MaterializeTemporaryExpr *
CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary,
bool BoundToLvalueReference);

ExprResult ActOnFinishFullExpr(Expr *Expr) {
return ActOnFinishFullExpr(Expr, Expr ? Expr->getExprLoc()
: SourceLocation());
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/Expr.cpp
Expand Up @@ -2890,7 +2890,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXThrowExprClass:
case CXXNewExprClass:
case CXXDeleteExprClass:
case ExprWithCleanupsClass:
case CoawaitExprClass:
case CoyieldExprClass:
// These always have a side-effect.
Expand All @@ -2903,6 +2902,12 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
return Finder.hasSideEffects();
}

case ExprWithCleanupsClass:
if (IncludePossibleEffects)
if (cast<ExprWithCleanups>(this)->cleanupsHaveSideEffects())
return true;
break;

case ParenExprClass:
case ArraySubscriptExprClass:
case OMPArraySectionExprClass:
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/AST/ExprCXX.cpp
Expand Up @@ -1039,23 +1039,27 @@ bool LambdaExpr::isMutable() const {
}

ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
bool CleanupsHaveSideEffects,
ArrayRef<CleanupObject> objects)
: Expr(ExprWithCleanupsClass, subexpr->getType(),
subexpr->getValueKind(), subexpr->getObjectKind(),
subexpr->isTypeDependent(), subexpr->isValueDependent(),
subexpr->isInstantiationDependent(),
subexpr->containsUnexpandedParameterPack()),
SubExpr(subexpr) {
ExprWithCleanupsBits.CleanupsHaveSideEffects = CleanupsHaveSideEffects;
ExprWithCleanupsBits.NumObjects = objects.size();
for (unsigned i = 0, e = objects.size(); i != e; ++i)
getTrailingObjects<CleanupObject>()[i] = objects[i];
}

ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr,
bool CleanupsHaveSideEffects,
ArrayRef<CleanupObject> objects) {
void *buffer = C.Allocate(totalSizeToAlloc<CleanupObject>(objects.size()),
llvm::alignOf<ExprWithCleanups>());
return new (buffer) ExprWithCleanups(subexpr, objects);
return new (buffer)
ExprWithCleanups(subexpr, CleanupsHaveSideEffects, objects);
}

ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Analysis/Consumed.cpp
Expand Up @@ -466,9 +466,15 @@ class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
MapType PropagationMap;

InfoEntry findInfo(const Expr *E) {
if (auto Cleanups = dyn_cast<ExprWithCleanups>(E))
if (!Cleanups->cleanupsHaveSideEffects())
E = Cleanups->getSubExpr();
return PropagationMap.find(E->IgnoreParens());
}
ConstInfoEntry findInfo(const Expr *E) const {
if (auto Cleanups = dyn_cast<ExprWithCleanups>(E))
if (!Cleanups->cleanupsHaveSideEffects())
E = Cleanups->getSubExpr();
return PropagationMap.find(E->IgnoreParens());
}
void insertInfo(const Expr *E, const PropagationInfo &PI) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGExprConstant.cpp
Expand Up @@ -764,6 +764,12 @@ class ConstExprEmitter :
return Visit(DIE->getExpr());
}

llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E) {
if (!E->cleanupsHaveSideEffects())
return Visit(E->getSubExpr());
return nullptr;
}

llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
return Visit(E->GetTemporaryExpr());
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/Sema.cpp
Expand Up @@ -88,7 +88,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr),
VisContext(nullptr),
IsBuildingRecoveryCallExpr(false),
ExprNeedsCleanups(false), LateTemplateParser(nullptr),
Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr),
CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
Expand Down Expand Up @@ -124,7 +124,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Tell diagnostics how to render things from the AST library.
Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context);

ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, false, nullptr, false);
ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, CleanupInfo{}, nullptr,
false);

FunctionScopes.push_back(new FunctionScopeInfo(Diags));

Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Sema/SemaCast.cpp
Expand Up @@ -641,8 +641,8 @@ void CastOperation::CheckDynamicCast() {
// If we're dynamic_casting from a prvalue to an rvalue reference, we need
// to materialize the prvalue before we bind the reference to it.
if (SrcExpr.get()->isRValue())
SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
SrcType, SrcExpr.get(), /*IsLValueReference*/false);
SrcExpr = Self.CreateMaterializeTemporaryExpr(
SrcType, SrcExpr.get(), /*IsLValueReference*/ false);
SrcPointee = SrcType;
}

Expand Down Expand Up @@ -1649,8 +1649,8 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
if (NeedToMaterializeTemporary)
// This is a const_cast from a class prvalue to an rvalue reference type.
// Materialize a temporary to store the result of the conversion.
SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
SrcType, SrcExpr.get(), /*IsLValueReference*/ false);
SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
/*IsLValueReference*/ false);

return TC_Success;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaCoroutine.cpp
Expand Up @@ -244,7 +244,7 @@ ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
// If the expression is a temporary, materialize it as an lvalue so that we
// can use it multiple times.
if (E->getValueKind() == VK_RValue)
E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
E = CreateMaterializeTemporaryExpr(E->getType(), E, true);

// Build the await_ready, await_suspend, await_resume calls.
ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
Expand Down Expand Up @@ -311,7 +311,7 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
// If the expression is a temporary, materialize it as an lvalue so that we
// can use it multiple times.
if (E->getValueKind() == VK_RValue)
E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
E = CreateMaterializeTemporaryExpr(E->getType(), E, true);

// Build the await_ready, await_suspend, await_resume calls.
ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -11648,7 +11648,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
assert(ExprCleanupObjects.size() ==
ExprEvalContexts.back().NumCleanupObjects &&
"Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
assert(!Cleanup.exprNeedsCleanups() && "Unaccounted cleanups in function");
assert(MaybeODRUseExprs.empty() &&
"Leftover expressions for odr-use checking");
}
Expand Down

0 comments on commit f120a7b

Please sign in to comment.