From fe31481f6829eaebf40205a1695a7aa68f0de36c Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 21 Jun 2011 17:03:29 +0000 Subject: [PATCH] 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 . llvm-svn: 133521 --- clang/include/clang/AST/Decl.h | 14 +++++ clang/include/clang/AST/ExprCXX.h | 58 +++++++++++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 1 + clang/include/clang/Basic/StmtNodes.td | 1 + .../include/clang/Serialization/ASTBitCodes.h | 3 +- clang/lib/AST/Decl.cpp | 14 +++++ clang/lib/AST/Expr.cpp | 53 ++++++++++++++++- clang/lib/AST/ExprClassification.cpp | 5 ++ clang/lib/AST/ExprConstant.cpp | 1 + clang/lib/AST/ItaniumMangle.cpp | 5 ++ clang/lib/AST/StmtPrinter.cpp | 4 ++ clang/lib/AST/StmtProfile.cpp | 5 ++ clang/lib/Analysis/CFG.cpp | 6 +- clang/lib/CodeGen/CGExpr.cpp | 18 +++++- clang/lib/CodeGen/CGExprAgg.cpp | 6 +- clang/lib/CodeGen/CGExprConstant.cpp | 4 ++ clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/lib/Sema/SemaChecking.cpp | 16 +++++ clang/lib/Sema/SemaInit.cpp | 5 +- clang/lib/Sema/TreeTransform.h | 7 +++ clang/lib/Serialization/ASTReaderStmt.cpp | 10 ++++ clang/lib/Serialization/ASTWriterStmt.cpp | 7 +++ .../Checkers/IteratorsChecker.cpp | 27 ++++++--- clang/lib/StaticAnalyzer/Core/Environment.cpp | 3 + clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 24 ++++---- clang/test/CodeGenCXX/references.cpp | 28 +++++++++ clang/tools/libclang/CXCursor.cpp | 1 + 27 files changed, 300 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 2cc8ec16fff7..143915b4b54c 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -979,6 +979,20 @@ public: void setInit(Expr *I); + /// \brief Determine whether this variable is a reference that + /// extends the lifetime of its temporary initializer. + /// + /// A reference extends the lifetime of its temporary initializer if + /// it's initializer is an rvalue that would normally go out of scope + /// at the end of the initializer (a full expression). In such cases, + /// the reference itself takes ownership of the temporary, which will + /// be destroyed when the reference goes out of scope. For example: + /// + /// \code + /// const int &r = 1.0; // creates a temporary of type 'int' + /// \endcode + bool extendsLifetimeOfTemporary() const; + EvaluatedStmt *EnsureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast(); if (!Eval) { diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index a97057973745..1b1019e5546d 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -2987,6 +2987,64 @@ public: // Iterators child_range children() { return child_range(); } }; + +/// \brief Represents a prvalue temporary that written into memory so that +/// a reference can bind to it. +/// +/// Prvalue expressions are materialized when they need to have an address +/// in memory for a reference to bind to. This happens when binding a +/// reference to the result of a conversion, e.g., +/// +/// \code +/// const int &r = 1.0; +/// \endcode +/// +/// Here, 1.0 is implicitly converted to an \c int. That resulting \c int is +/// then materialized via a \c MaterializeTemporaryExpr, and the reference +/// binds to the temporary. \c MaterializeTemporaryExprs are always glvalues +/// (either an lvalue or an xvalue, depending on the kind of reference binding +/// to it), maintaining the invariant that references always bind to glvalues. +class MaterializeTemporaryExpr : public Expr { + /// \brief The temporary-generating expression whose value will be + /// materialized. + Stmt *Temporary; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + MaterializeTemporaryExpr(Expr *Temporary, bool BoundToLvalueReference) + : Expr(MaterializeTemporaryExprClass, Temporary->getType(), + BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->containsUnexpandedParameterPack()), + Temporary(Temporary) { } + + MaterializeTemporaryExpr(EmptyShell Empty) + : Expr(MaterializeTemporaryExprClass, Empty) { } + + /// \brief Retrieve the temporary-generating subexpression whose value will + /// be materialized into a glvalue. + Expr *GetTemporaryExpr() const { return reinterpret_cast(Temporary); } + + /// \brief Determine whether this materialized temporary is bound to an + /// lvalue reference; otherwise, it's bound to an rvalue reference. + bool BoundToLvalueReference() const { + return getValueKind() == VK_LValue; + } + + SourceRange getSourceRange() const { return Temporary->getSourceRange(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MaterializeTemporaryExprClass; + } + static bool classof(const MaterializeTemporaryExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(&Temporary, &Temporary + 1); } +}; } // end namespace clang diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1a30df6d8b83..7cdb0adc65d3 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1978,6 +1978,7 @@ DEF_TRAVERSE_STMT(CXXNoexceptExpr, { }) DEF_TRAVERSE_STMT(PackExpansionExpr, { }) DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) +DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { }) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, { }) diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index f503950c20e9..c07953eecae9 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -121,6 +121,7 @@ def CXXNoexceptExpr : DStmt; def PackExpansionExpr : DStmt; def SizeOfPackExpr : DStmt; def SubstNonTypeTemplateParmPackExpr : DStmt; +def MaterializeTemporaryExpr : DStmt; // Obj-C Expressions. def ObjCStringLiteral : DStmt; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 12f701e4605d..15fe3c61ae39 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1004,7 +1004,8 @@ namespace clang { EXPR_PACK_EXPANSION, // PackExpansionExpr EXPR_SIZEOF_PACK, // SizeOfPackExpr EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr - + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index c2abe1a5a90d..cdec049cb12a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1312,6 +1312,20 @@ void VarDecl::setInit(Expr *I) { Init = I; } +bool VarDecl::extendsLifetimeOfTemporary() const { + if (!getType()->isReferenceType()) + return false; + + const Expr *E = getInit(); + if (!E) + return false; + + if (const ExprWithCleanups *Cleanups = dyn_cast(E)) + E = Cleanups->getSubExpr(); + + return isa(E); +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast(MSI->getInstantiatedFrom()); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 2f303da7b5a6..31972bdd23e0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/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(SubExpr)) + SubExpr = Materialize->GetTemporaryExpr(); + // Skip any temporary bindings; they're implicit. if (CXXBindTemporaryExpr *Binder = dyn_cast(SubExpr)) SubExpr = Binder->getSubExpr(); @@ -1568,6 +1573,10 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return (cast(this) ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + case MaterializeTemporaryExprClass: + return cast(this)->GetTemporaryExpr() + ->isUnusedResultAWarning(Loc, R1, R2, Ctx); + case CXXDefaultArgExprClass: return (cast(this) ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); @@ -1599,6 +1608,9 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case ImplicitCastExprClass: return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case MaterializeTemporaryExprClass: + return cast(E)->GetTemporaryExpr() + ->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: return cast(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(E)) { + E = Materialize->GetTemporaryExpr(); + continue; + } + return E; } } @@ -1982,6 +2001,10 @@ Expr *Expr::IgnoreParenLValueCasts() { E = P->getResultExpr(); continue; } + } else if (MaterializeTemporaryExpr *Materialize + = dyn_cast(E)) { + E = Materialize->GetTemporaryExpr(); + continue; } break; } @@ -2011,6 +2034,11 @@ Expr *Expr::IgnoreParenImpCasts() { continue; } } + if (MaterializeTemporaryExpr *Materialize + = dyn_cast(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(E)) + E = M->GetTemporaryExpr(); + while (const ImplicitCastExpr *ICE = dyn_cast(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(E)) + E = M->GetTemporaryExpr(); + while (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); @@ -2170,6 +2204,12 @@ bool Expr::isImplicitCXXThis() const { } } + if (const MaterializeTemporaryExpr *M + = dyn_cast(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(this)->GetTemporaryExpr() + ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); } @@ -2360,6 +2404,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx, } else if (isa(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; + } else if (const MaterializeTemporaryExpr *M + = dyn_cast(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(e)) e = ewc->getSubExpr(); + if (const MaterializeTemporaryExpr *m = dyn_cast(e)) + e = m->GetTemporaryExpr(); e = cast(e)->getArg(0); while (const ImplicitCastExpr *ice = dyn_cast(e)) e = ice->getSubExpr(); diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 1a1fa91a40a5..2d824ce8fd77 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -341,6 +341,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::PackExpansionExprClass: return ClassifyInternal(Ctx, cast(E)->getPattern()); + + case Expr::MaterializeTemporaryExprClass: + return cast(E)->BoundToLvalueReference() + ? Cl::CL_LValue + : Cl::CL_XValue; } llvm_unreachable("unhandled expression kind in classification"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 432ffee08de5..7d2ea13d0a74 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2787,6 +2787,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: + case Expr::MaterializeTemporaryExprClass: return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5f0b2a6eff82..92e166a34a33 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2591,6 +2591,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { } break; } + + case Expr::MaterializeTemporaryExprClass: { + mangleExpression(cast(E)->GetTemporaryExpr()); + break; + } } } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index d6a67b13ef7b..f8edaf7ccf22 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1413,6 +1413,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr( OS << Node->getParameterPack()->getNameAsString(); } +void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){ + PrintExpr(Node->GetTemporaryExpr()); +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 52b5a103e792..7c1aa9c6f7e8 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -911,6 +911,11 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr( VisitTemplateArgument(S->getArgumentPack()); } +void StmtProfiler::VisitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { VisitExpr(E); } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 3e540203eaa0..f231c147f11e 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -776,7 +776,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD, QT = RT->getPointeeType(); if (!QT.isConstQualified()) return Scope; - if (!VD->getInit() || !VD->getInit()->Classify(*Context).isRValue()) + if (!VD->extendsLifetimeOfTemporary()) return Scope; } @@ -2763,6 +2763,10 @@ tryAgain: case Stmt::ParenExprClass: E = cast(E)->getSubExpr(); goto tryAgain; + + case Stmt::MaterializeTemporaryExprClass: + E = cast(E)->GetTemporaryExpr(); + goto tryAgain; } } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 20ccdb7f9cb8..d5c18eba70ae 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -207,6 +207,10 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, const NamedDecl *InitializedDecl) { ObjCARCReferenceLifetimeType = QualType(); + // Look through expressions for materialized temporaries (for now). + if (isa(E)) + E = cast(E)->GetTemporaryExpr(); + if (const CXXDefaultArgExpr *DAE = dyn_cast(E)) E = DAE->getExpr(); @@ -667,6 +671,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::CXXConstCastExprClass: case Expr::ObjCBridgedCastExprClass: return EmitCastLValue(cast(E)); + + case Expr::MaterializeTemporaryExprClass: + return EmitMaterializeTemporaryExpr(cast(E)); } } @@ -2067,11 +2074,20 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) { return getOpaqueLValueMapping(e); } +LValue CodeGenFunction::EmitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *E) { + RValue RV = EmitReferenceBindingToExpr(E->GetTemporaryExpr(), + /*InitializedDecl=*/0); + return LValue::MakeAddr(RV.getScalarVal(), E->getType(), + CGM.getContext().getTypeAlign(E->getType()), + CGM.getContext()); +} + + //===--------------------------------------------------------------------===// // Expression Emission //===--------------------------------------------------------------------===// - RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue) { if (CGDebugInfo *DI = getDebugInfo()) { diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index b1ac731f2134..1cd196a0e48a 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -129,7 +129,7 @@ public: void VisitExprWithCleanups(ExprWithCleanups *E); void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); } - + void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); void VisitOpaqueValueExpr(OpaqueValueExpr *E); void VisitVAArgExpr(VAArgExpr *E); @@ -241,6 +241,10 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { // Visitor Methods //===----------------------------------------------------------------------===// +void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){ + Visit(E->GetTemporaryExpr()); +} + void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) { EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e)); } diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 5184f4753751..e88c28737c61 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -662,6 +662,10 @@ public: return Visit(DAE->getExpr()); } + llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { + return Visit(E->GetTemporaryExpr()); + } + llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { unsigned NumInitElements = ILE->getNumInits(); if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() && diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index f34a70c5d9e7..e72d6ced921e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1850,6 +1850,7 @@ public: LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E); + LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 54900e0cf15c..1b9fd7769bd4 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2205,6 +2205,14 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl &refVars) { return NULL; } + case Stmt::MaterializeTemporaryExprClass: + if (Expr *Result = EvalAddr( + cast(E)->GetTemporaryExpr(), + refVars)) + return Result; + + return E; + // Everything else: we simply don't reason about them. default: return NULL; @@ -2306,6 +2314,14 @@ do { return EvalVal(M->getBase(), refVars); } + case Stmt::MaterializeTemporaryExprClass: + if (Expr *Result = EvalVal( + cast(E)->GetTemporaryExpr(), + refVars)) + return Result; + + return E; + default: // Check that we don't return or take the address of a reference to a // temporary. This is only useful in C++. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5bdadc6166b1..3231455f5a5c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4075,12 +4075,13 @@ InitializationSequence::Perform(Sema &S, break; case SK_BindReferenceToTemporary: - // Reference binding does not have any corresponding ASTs. - // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); + // Materialize the temporary into memory. + CurInit = new (S.Context) MaterializeTemporaryExpr(CurInit.get(), + Entity.getType()->isLValueReferenceType()); break; case SK_ExtraneousCopyToTemporary: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 121ff00628c2..b8060277ed34 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -7655,6 +7655,13 @@ TreeTransform::TransformSubstNonTypeTemplateParmPackExpr( return SemaRef.Owned(E); } +template +ExprResult +TreeTransform::TransformMaterializeTemporaryExpr( + MaterializeTemporaryExpr *E) { + return getDerived().TransformExpr(E->GetTemporaryExpr()); +} + template ExprResult TreeTransform::TransformObjCStringLiteral(ObjCStringLiteral *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 0af3546223ce..f6c27d410685 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -189,6 +189,7 @@ namespace clang { void VisitSizeOfPackExpr(SizeOfPackExpr *E); void VisitSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); + void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); void VisitOpaqueValueExpr(OpaqueValueExpr *E); // CUDA Expressions @@ -1426,6 +1427,11 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( E->NameLoc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { + VisitExpr(E); + E->Temporary = Reader.ReadSubExpr(); +} + void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); Idx++; // skip ID @@ -2014,6 +2020,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty); break; + case EXPR_MATERIALIZE_TEMPORARY: + S = new (Context) MaterializeTemporaryExpr(Empty); + break; + case EXPR_OPAQUE_VALUE: { unsigned key = Record[ASTStmtReader::NumExprFields]; OpaqueValueExpr *&expr = OpaqueValueExprs[key]; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index c6d182d42545..b66fdfa558d8 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -164,6 +164,7 @@ namespace clang { void VisitSizeOfPackExpr(SizeOfPackExpr *E); void VisitSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); + void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); void VisitOpaqueValueExpr(OpaqueValueExpr *E); // CUDA Expressions @@ -1443,6 +1444,12 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr( Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK; } +void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->Temporary); + Code = serialization::EXPR_MATERIALIZE_TEMPORARY; +} + void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); Record.push_back(Writer.getOpaqueValueID(E)); diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp index e4e5f54770b3..de6da4f8c377 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp @@ -237,8 +237,11 @@ const GRState *IteratorsChecker::invalidateIterators(const GRState *state, const GRState *IteratorsChecker::handleAssign(const GRState *state, const Expr *lexp, const Expr *rexp, const LocationContext *LC) const { // Skip the cast if present. - if (isa(lexp)) - lexp = dyn_cast(lexp)->getSubExpr(); + if (const MaterializeTemporaryExpr *M + = dyn_cast(lexp)) + lexp = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast(lexp)) + lexp = ICE->getSubExpr(); SVal sv = state->getSVal(lexp); const MemRegion *MR = sv.getAsRegion(); if (!MR) @@ -260,8 +263,11 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state, const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const { // Assume unknown until we find something definite. state = state->set(MR, RefState::getUnknown()); - if (isa(rexp)) - rexp = dyn_cast(rexp)->getSubExpr(); + if (const MaterializeTemporaryExpr *M + = dyn_cast(rexp)) + rexp = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast(rexp)) + rexp = ICE->getSubExpr(); // Need to handle three cases: MemberCall, copy, copy with addition. if (const CallExpr *CE = dyn_cast(rexp)) { // Handle MemberCall. @@ -347,8 +353,10 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const { E = CE->getArg(0); } } - if (isa(E)) - E = dyn_cast(E)->getSubExpr(); + if (const MaterializeTemporaryExpr *M = dyn_cast(E)) + E = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast(E)) + E = ICE->getSubExpr(); // If it isn't one of our types, don't do anything. if (getTemplateKind(E->getType()) != VectorIteratorKind) return NULL; @@ -520,8 +528,11 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS, if (const CXXConstructExpr *CE = dyn_cast(InitEx)) { if (CE->getNumArgs() == 1) { const Expr *E = CE->getArg(0); - if (isa(E)) - InitEx = dyn_cast(E)->getSubExpr(); + if (const MaterializeTemporaryExpr *M + = dyn_cast(E)) + E = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast(E)) + InitEx = ICE->getSubExpr(); state = handleAssign(state, MR, InitEx, C.getPredecessor()->getLocationContext()); } diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp index 48f126bfd863..3961c7b95259 100644 --- a/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -83,6 +83,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, case Stmt::CXXBindTemporaryExprClass: E = cast(E)->getSubExpr(); continue; + case Stmt::MaterializeTemporaryExprClass: + E = cast(E)->GetTemporaryExpr(); + continue; // Handle all other Stmt* using a lookup. default: break; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 21efbac6996b..4aa5e350bc1b 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -700,6 +700,16 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } + case Expr::MaterializeTemporaryExprClass: { + const MaterializeTemporaryExpr *Materialize + = cast(S); + if (!Materialize->getType()->isRecordType()) + CreateCXXTemporaryObject(Materialize->GetTemporaryExpr(), Pred, Dst); + else + Visit(Materialize->GetTemporaryExpr(), Pred, Dst); + break; + } + case Stmt::InitListExprClass: VisitInitListExpr(cast(S), Pred, Dst); break; @@ -2306,17 +2316,9 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, // time a function is called those values may not be current. ExplodedNodeSet Tmp; - if (InitEx) { - if (VD->getType()->isReferenceType() && !InitEx->isLValue()) { - // If the initializer is C++ record type, it should already has a - // temp object. - if (!InitEx->getType()->isRecordType()) - CreateCXXTemporaryObject(InitEx, Pred, Tmp); - else - Tmp.Add(Pred); - } else - Visit(InitEx, Pred, Tmp); - } else + if (InitEx) + Visit(InitEx, Pred, Tmp); + else Tmp.Add(Pred); ExplodedNodeSet Tmp2; diff --git a/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp index 25bc8d801790..d53815ded714 100644 --- a/clang/test/CodeGenCXX/references.cpp +++ b/clang/test/CodeGenCXX/references.cpp @@ -269,3 +269,31 @@ void h() { f(g().b); } } + +// PR9565 +namespace PR9565 { + struct a { int a : 10, b : 10; }; + // CHECK: define void @_ZN6PR95651fEv() + void f() { + // CHECK: call void @llvm.memcpy + a x = { 0, 0 }; + // CHECK: [[WITH_SEVENTEEN:%[a-zA-Z0-9]+]] = or i32 [[WITHOUT_SEVENTEEN:%[a-zA-Z0-9]+]], 17 + // CHECK: store i32 [[WITH_SEVENTEEN]], i32* [[XA:%[a-zA-Z0-9]+]] + x.a = 17; + // CHECK-NEXT: bitcast + // CHECK-NEXT: load + // CHECK-NEXT: and + // CHECK-NEXT: shl + // CHECK-NEXT: ashr + // CHECK-NEXT: store i32 + // CHECK-NEXT: store i32* + const int &y = x.a; + // CHECK-NEXT: bitcast + // CHECK-NEXT: load + // CHECK-NEXT: and + // CHECK-NEXT: or + // CHECK-NEXT: store i32 + x.b = 19; + // CHECK-NEXT: ret void + } +} diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 351345134192..f2ee2a922597 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -100,6 +100,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: + case Stmt::MaterializeTemporaryExprClass: K = CXCursor_UnexposedStmt; break;