diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-06-21 17:03:29 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-06-21 17:03:29 +0000 |
commit | 03e80030515c800d1ab44125b9052dfffd1bd04c (patch) | |
tree | 4ef971a4ce700937aabf19c08f2bfd4f826a7a91 /lib/AST/Expr.cpp | |
parent | 65aa6885818d4b4eea2e5a9d12085b2398148662 (diff) |
Introduce a new AST node describing reference binding to temporaries.
MaterializeTemporaryExpr captures a reference binding to a temporary
value, making explicit that the temporary value (a prvalue) needs to
be materialized into memory so that its address can be used. The
intended AST invariant here is that a reference will always bind to a
glvalue, and MaterializeTemporaryExpr will be used to convert prvalues
into glvalues for that binding to happen. For example, given
const int& r = 1.0;
The initializer of "r" will be a MaterializeTemporaryExpr whose
subexpression is an implicit conversion from the double literal "1.0"
to an integer value.
IR generation benefits most from this new node, since it was
previously guessing (badly) when to materialize temporaries for the
purposes of reference binding. There are likely more refactoring and
cleanups we could perform there, but the introduction of
MaterializeTemporaryExpr fixes PR9565, a case where IR generation
would effectively bind a const reference directly to a bitfield in a
struct. Addresses <rdar://problem/9552231>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133521 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/Expr.cpp')
-rw-r--r-- | lib/AST/Expr.cpp | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 2f303da7b5..31972bdd23 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1060,7 +1060,12 @@ Expr *CastExpr::getSubExprAsWritten() { CastExpr *E = this; do { SubExpr = E->getSubExpr(); - + + // Skip through reference binding to temporary. + if (MaterializeTemporaryExpr *Materialize + = dyn_cast<MaterializeTemporaryExpr>(SubExpr)) + SubExpr = Materialize->GetTemporaryExpr(); + // Skip any temporary bindings; they're implicit. if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) SubExpr = Binder->getSubExpr(); @@ -1568,6 +1573,10 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return (cast<ImplicitCastExpr>(this) ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + case MaterializeTemporaryExprClass: + return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() + ->isUnusedResultAWarning(Loc, R1, R2, Ctx); + case CXXDefaultArgExprClass: return (cast<CXXDefaultArgExpr>(this) ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); @@ -1599,6 +1608,9 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case ImplicitCastExprClass: return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case MaterializeTemporaryExprClass: + return cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr() + ->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case DeclRefExprClass: { @@ -1873,7 +1885,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXStaticCastExprClass: case CXXFunctionalCastExprClass: case BinaryOperatorClass: - case CompoundAssignOperatorClass: { + case CompoundAssignOperatorClass: + case MaterializeTemporaryExprClass: { CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot; return MergeCanThrow(CT, CanSubExprsThrow(C, this)); } @@ -1953,6 +1966,12 @@ Expr *Expr::IgnoreParenCasts() { continue; } } + if (MaterializeTemporaryExpr *Materialize + = dyn_cast<MaterializeTemporaryExpr>(E)) { + E = Materialize->GetTemporaryExpr(); + continue; + } + return E; } } @@ -1982,6 +2001,10 @@ Expr *Expr::IgnoreParenLValueCasts() { E = P->getResultExpr(); continue; } + } else if (MaterializeTemporaryExpr *Materialize + = dyn_cast<MaterializeTemporaryExpr>(E)) { + E = Materialize->GetTemporaryExpr(); + continue; } break; } @@ -2011,6 +2034,11 @@ Expr *Expr::IgnoreParenImpCasts() { continue; } } + if (MaterializeTemporaryExpr *Materialize + = dyn_cast<MaterializeTemporaryExpr>(E)) { + E = Materialize->GetTemporaryExpr(); + continue; + } return E; } } @@ -2074,6 +2102,9 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { bool Expr::isDefaultArgument() const { const Expr *E = this; + if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) + E = M->GetTemporaryExpr(); + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExprAsWritten(); @@ -2083,6 +2114,9 @@ bool Expr::isDefaultArgument() const { /// \brief Skip over any no-op casts and any temporary-binding /// expressions. static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { + if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) + E = M->GetTemporaryExpr(); + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); @@ -2170,6 +2204,12 @@ bool Expr::isImplicitCXXThis() const { } } + if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(E)) { + E = M->GetTemporaryExpr(); + continue; + } + break; } @@ -2302,6 +2342,10 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { ->isConstantInitializer(Ctx, false); break; + + case MaterializeTemporaryExprClass: + return llvm::cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() + ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); } @@ -2360,6 +2404,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx, } else if (isa<GNUNullExpr>(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; + } else if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(this)) { + return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC); } // C++0x nullptr_t is always a null pointer constant. @@ -3011,6 +3058,8 @@ ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e)) e = ewc->getSubExpr(); + if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e)) + e = m->GetTemporaryExpr(); e = cast<CXXConstructExpr>(e)->getArg(0); while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) e = ice->getSubExpr(); |