Prechádzať zdrojové kódy

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
Douglas Gregor 14 rokov pred
rodič
commit
03e8003051

+ 14 - 0
include/clang/AST/Decl.h

@@ -979,6 +979,20 @@ public:
 
 
   void setInit(Expr *I);
   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 *EnsureEvaluatedStmt() const {
     EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
     EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
     if (!Eval) {
     if (!Eval) {

+ 58 - 0
include/clang/AST/ExprCXX.h

@@ -2987,6 +2987,64 @@ public:
   // Iterators
   // Iterators
   child_range children() { return child_range(); }
   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<Expr *>(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
 }  // end namespace clang
 
 

+ 1 - 0
include/clang/AST/RecursiveASTVisitor.h

@@ -1978,6 +1978,7 @@ DEF_TRAVERSE_STMT(CXXNoexceptExpr, { })
 DEF_TRAVERSE_STMT(PackExpansionExpr, { })
 DEF_TRAVERSE_STMT(PackExpansionExpr, { })
 DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
 DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
 DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
 DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
+DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
 
 
 // These literals (all of them) do not need any action.
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, { })
 DEF_TRAVERSE_STMT(IntegerLiteral, { })

+ 1 - 0
include/clang/Basic/StmtNodes.td

@@ -121,6 +121,7 @@ def CXXNoexceptExpr : DStmt<Expr>;
 def PackExpansionExpr : DStmt<Expr>;
 def PackExpansionExpr : DStmt<Expr>;
 def SizeOfPackExpr : DStmt<Expr>;
 def SizeOfPackExpr : DStmt<Expr>;
 def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
 def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
+def MaterializeTemporaryExpr : DStmt<Expr>;
 
 
 // Obj-C Expressions.
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
 def ObjCStringLiteral : DStmt<Expr>;

+ 2 - 1
include/clang/Serialization/ASTBitCodes.h

@@ -1004,7 +1004,8 @@ namespace clang {
       EXPR_PACK_EXPANSION,        // PackExpansionExpr
       EXPR_PACK_EXPANSION,        // PackExpansionExpr
       EXPR_SIZEOF_PACK,           // SizeOfPackExpr
       EXPR_SIZEOF_PACK,           // SizeOfPackExpr
       EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
       EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
-
+      EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
+      
       // CUDA
       // CUDA
       EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
       EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
 
 

+ 14 - 0
lib/AST/Decl.cpp

@@ -1312,6 +1312,20 @@ void VarDecl::setInit(Expr *I) {
   Init = 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<ExprWithCleanups>(E))
+    E = Cleanups->getSubExpr();
+  
+  return isa<MaterializeTemporaryExpr>(E);
+}
+
 VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
 VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return cast<VarDecl>(MSI->getInstantiatedFrom());
     return cast<VarDecl>(MSI->getInstantiatedFrom());

+ 51 - 2
lib/AST/Expr.cpp

@@ -1060,7 +1060,12 @@ Expr *CastExpr::getSubExprAsWritten() {
   CastExpr *E = this;
   CastExpr *E = this;
   do {
   do {
     SubExpr = E->getSubExpr();
     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.
     // Skip any temporary bindings; they're implicit.
     if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
     if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
       SubExpr = Binder->getSubExpr();
       SubExpr = Binder->getSubExpr();
@@ -1568,6 +1573,10 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
     return (cast<ImplicitCastExpr>(this)
     return (cast<ImplicitCastExpr>(this)
             ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
             ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
 
 
+  case MaterializeTemporaryExprClass:
+    return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
+                                    ->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+      
   case CXXDefaultArgExprClass:
   case CXXDefaultArgExprClass:
     return (cast<CXXDefaultArgExpr>(this)
     return (cast<CXXDefaultArgExpr>(this)
             ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
             ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
@@ -1599,6 +1608,9 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
     return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
     return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
   case ImplicitCastExprClass:
   case ImplicitCastExprClass:
     return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
     return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
+  case MaterializeTemporaryExprClass:
+    return cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()
+                                                      ->isOBJCGCCandidate(Ctx);
   case CStyleCastExprClass:
   case CStyleCastExprClass:
     return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
     return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
   case DeclRefExprClass: {
   case DeclRefExprClass: {
@@ -1873,7 +1885,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
   case CXXStaticCastExprClass:
   case CXXStaticCastExprClass:
   case CXXFunctionalCastExprClass:
   case CXXFunctionalCastExprClass:
   case BinaryOperatorClass:
   case BinaryOperatorClass:
-  case CompoundAssignOperatorClass: {
+  case CompoundAssignOperatorClass:
+  case MaterializeTemporaryExprClass: {
     CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
     CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
     return MergeCanThrow(CT, CanSubExprsThrow(C, this));
     return MergeCanThrow(CT, CanSubExprsThrow(C, this));
   }
   }
@@ -1953,6 +1966,12 @@ Expr *Expr::IgnoreParenCasts() {
         continue;
         continue;
       }
       }
     }
     }
+    if (MaterializeTemporaryExpr *Materialize 
+                                      = dyn_cast<MaterializeTemporaryExpr>(E)) {
+      E = Materialize->GetTemporaryExpr();
+      continue;
+    }
+      
     return E;
     return E;
   }
   }
 }
 }
@@ -1982,6 +2001,10 @@ Expr *Expr::IgnoreParenLValueCasts() {
         E = P->getResultExpr();
         E = P->getResultExpr();
         continue;
         continue;
       }
       }
+    } else if (MaterializeTemporaryExpr *Materialize 
+                                      = dyn_cast<MaterializeTemporaryExpr>(E)) {
+      E = Materialize->GetTemporaryExpr();
+      continue;
     }
     }
     break;
     break;
   }
   }
@@ -2011,6 +2034,11 @@ Expr *Expr::IgnoreParenImpCasts() {
         continue;
         continue;
       }
       }
     }
     }
+    if (MaterializeTemporaryExpr *Materialize 
+                                      = dyn_cast<MaterializeTemporaryExpr>(E)) {
+      E = Materialize->GetTemporaryExpr();
+      continue;
+    }
     return E;
     return E;
   }
   }
 }
 }
@@ -2074,6 +2102,9 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
 
 
 bool Expr::isDefaultArgument() const {
 bool Expr::isDefaultArgument() const {
   const Expr *E = this;
   const Expr *E = this;
+  if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
+    E = M->GetTemporaryExpr();
+
   while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
   while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
     E = ICE->getSubExprAsWritten();
     E = ICE->getSubExprAsWritten();
   
   
@@ -2083,6 +2114,9 @@ bool Expr::isDefaultArgument() const {
 /// \brief Skip over any no-op casts and any temporary-binding
 /// \brief Skip over any no-op casts and any temporary-binding
 /// expressions.
 /// expressions.
 static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
 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)) {
   while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
     if (ICE->getCastKind() == CK_NoOp)
     if (ICE->getCastKind() == CK_NoOp)
       E = ICE->getSubExpr();
       E = ICE->getSubExpr();
@@ -2170,6 +2204,12 @@ bool Expr::isImplicitCXXThis() const {
       }
       }
     }
     }
     
     
+    if (const MaterializeTemporaryExpr *M
+                                      = dyn_cast<MaterializeTemporaryExpr>(E)) {
+      E = M->GetTemporaryExpr();
+      continue;
+    }
+    
     break;
     break;
   }
   }
   
   
@@ -2302,6 +2342,10 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
         ->isConstantInitializer(Ctx, false);
         ->isConstantInitializer(Ctx, false);
       
       
     break;
     break;
+      
+  case MaterializeTemporaryExprClass:
+    return llvm::cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
+                                            ->isConstantInitializer(Ctx, false);
   }
   }
   return isEvaluatable(Ctx);
   return isEvaluatable(Ctx);
 }
 }
@@ -2360,6 +2404,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
   } else if (isa<GNUNullExpr>(this)) {
   } else if (isa<GNUNullExpr>(this)) {
     // The GNU __null extension is always a null pointer constant.
     // The GNU __null extension is always a null pointer constant.
     return NPCK_GNUNull;
     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.
   // 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) {
 const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
   if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
   if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
     e = ewc->getSubExpr();
     e = ewc->getSubExpr();
+  if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e))
+    e = m->GetTemporaryExpr();
   e = cast<CXXConstructExpr>(e)->getArg(0);
   e = cast<CXXConstructExpr>(e)->getArg(0);
   while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
   while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
     e = ice->getSubExpr();
     e = ice->getSubExpr();

+ 5 - 0
lib/AST/ExprClassification.cpp

@@ -341,6 +341,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
       
       
   case Expr::PackExpansionExprClass:
   case Expr::PackExpansionExprClass:
     return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
     return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
+      
+  case Expr::MaterializeTemporaryExprClass:
+    return cast<MaterializeTemporaryExpr>(E)->BoundToLvalueReference()
+              ? Cl::CL_LValue 
+              : Cl::CL_XValue;
   }
   }
   
   
   llvm_unreachable("unhandled expression kind in classification");
   llvm_unreachable("unhandled expression kind in classification");

+ 1 - 0
lib/AST/ExprConstant.cpp

@@ -2787,6 +2787,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
   case Expr::SubstNonTypeTemplateParmPackExprClass:
   case Expr::SubstNonTypeTemplateParmPackExprClass:
   case Expr::AsTypeExprClass:
   case Expr::AsTypeExprClass:
   case Expr::ObjCIndirectCopyRestoreExprClass:
   case Expr::ObjCIndirectCopyRestoreExprClass:
+  case Expr::MaterializeTemporaryExprClass:
     return ICEDiag(2, E->getLocStart());
     return ICEDiag(2, E->getLocStart());
 
 
   case Expr::SizeOfPackExprClass:
   case Expr::SizeOfPackExprClass:

+ 5 - 0
lib/AST/ItaniumMangle.cpp

@@ -2591,6 +2591,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
     }
     }
     break;
     break;
   }
   }
+      
+  case Expr::MaterializeTemporaryExprClass: {
+    mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
+    break;
+  }
   }
   }
 }
 }
 
 

+ 4 - 0
lib/AST/StmtPrinter.cpp

@@ -1413,6 +1413,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
   OS << Node->getParameterPack()->getNameAsString();
   OS << Node->getParameterPack()->getNameAsString();
 }
 }
 
 
+void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
+  PrintExpr(Node->GetTemporaryExpr());
+}
+
 // Obj-C
 // Obj-C
 
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {

+ 5 - 0
lib/AST/StmtProfile.cpp

@@ -911,6 +911,11 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
   VisitTemplateArgument(S->getArgumentPack());
   VisitTemplateArgument(S->getArgumentPack());
 }
 }
 
 
+void StmtProfiler::VisitMaterializeTemporaryExpr(
+                                           const MaterializeTemporaryExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
 void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
   VisitExpr(E);  
   VisitExpr(E);  
 }
 }

+ 5 - 1
lib/Analysis/CFG.cpp

@@ -776,7 +776,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD,
     QT = RT->getPointeeType();
     QT = RT->getPointeeType();
     if (!QT.isConstQualified())
     if (!QT.isConstQualified())
       return Scope;
       return Scope;
-    if (!VD->getInit() || !VD->getInit()->Classify(*Context).isRValue())
+    if (!VD->extendsLifetimeOfTemporary())
       return Scope;
       return Scope;
   }
   }
 
 
@@ -2763,6 +2763,10 @@ tryAgain:
     case Stmt::ParenExprClass:
     case Stmt::ParenExprClass:
       E = cast<ParenExpr>(E)->getSubExpr();
       E = cast<ParenExpr>(E)->getSubExpr();
       goto tryAgain;
       goto tryAgain;
+      
+    case Stmt::MaterializeTemporaryExprClass:
+      E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+      goto tryAgain;
   }
   }
 }
 }
 
 

+ 17 - 1
lib/CodeGen/CGExpr.cpp

@@ -207,6 +207,10 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
                             const NamedDecl *InitializedDecl) {
                             const NamedDecl *InitializedDecl) {
   ObjCARCReferenceLifetimeType = QualType();
   ObjCARCReferenceLifetimeType = QualType();
   
   
+  // Look through expressions for materialized temporaries (for now).
+  if (isa<MaterializeTemporaryExpr>(E))
+    E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+
   if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
   if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
     E = DAE->getExpr();
     E = DAE->getExpr();
   
   
@@ -667,6 +671,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
   case Expr::CXXConstCastExprClass:
   case Expr::CXXConstCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
     return EmitCastLValue(cast<CastExpr>(E));
     return EmitCastLValue(cast<CastExpr>(E));
+      
+  case Expr::MaterializeTemporaryExprClass:
+    return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
   }
   }
 }
 }
 
 
@@ -2067,11 +2074,20 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
   return getOpaqueLValueMapping(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
 //                             Expression Emission
 //===--------------------------------------------------------------------===//
 //===--------------------------------------------------------------------===//
 
 
-
 RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, 
 RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, 
                                      ReturnValueSlot ReturnValue) {
                                      ReturnValueSlot ReturnValue) {
   if (CGDebugInfo *DI = getDebugInfo()) {
   if (CGDebugInfo *DI = getDebugInfo()) {

+ 5 - 1
lib/CodeGen/CGExprAgg.cpp

@@ -129,7 +129,7 @@ public:
   void VisitExprWithCleanups(ExprWithCleanups *E);
   void VisitExprWithCleanups(ExprWithCleanups *E);
   void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
   void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
   void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
   void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
-
+  void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
   void VisitOpaqueValueExpr(OpaqueValueExpr *E);
   void VisitOpaqueValueExpr(OpaqueValueExpr *E);
 
 
   void VisitVAArgExpr(VAArgExpr *E);
   void VisitVAArgExpr(VAArgExpr *E);
@@ -241,6 +241,10 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
 //                            Visitor Methods
 //                            Visitor Methods
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 
 
+void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
+  Visit(E->GetTemporaryExpr());
+}
+
 void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
 void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
   EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e));
   EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e));
 }
 }

+ 4 - 0
lib/CodeGen/CGExprConstant.cpp

@@ -662,6 +662,10 @@ public:
     return Visit(DAE->getExpr());
     return Visit(DAE->getExpr());
   }
   }
 
 
+  llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+    return Visit(E->GetTemporaryExpr());
+  }
+
   llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
   llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
     unsigned NumInitElements = ILE->getNumInits();
     unsigned NumInitElements = ILE->getNumInits();
     if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() &&
     if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() &&

+ 1 - 0
lib/CodeGen/CodeGenFunction.h

@@ -1850,6 +1850,7 @@ public:
   LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
   LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
   LValue EmitCastLValue(const CastExpr *E);
   LValue EmitCastLValue(const CastExpr *E);
   LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
   LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
+  LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
   LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
   LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
 
 
   llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
   llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,

+ 16 - 0
lib/Sema/SemaChecking.cpp

@@ -2205,6 +2205,14 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
         return NULL;
         return NULL;
   }
   }
 
 
+  case Stmt::MaterializeTemporaryExprClass:
+    if (Expr *Result = EvalAddr(
+                         cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+                                refVars))
+      return Result;
+      
+    return E;
+      
   // Everything else: we simply don't reason about them.
   // Everything else: we simply don't reason about them.
   default:
   default:
     return NULL;
     return NULL;
@@ -2306,6 +2314,14 @@ do {
     return EvalVal(M->getBase(), refVars);
     return EvalVal(M->getBase(), refVars);
   }
   }
 
 
+  case Stmt::MaterializeTemporaryExprClass:
+    if (Expr *Result = EvalVal(
+                          cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+                               refVars))
+      return Result;
+      
+    return E;
+
   default:
   default:
     // Check that we don't return or take the address of a reference to a
     // Check that we don't return or take the address of a reference to a
     // temporary. This is only useful in C++.
     // temporary. This is only useful in C++.

+ 3 - 2
lib/Sema/SemaInit.cpp

@@ -4075,12 +4075,13 @@ InitializationSequence::Perform(Sema &S,
       break;
       break;
 
 
     case SK_BindReferenceToTemporary:
     case SK_BindReferenceToTemporary:
-      // Reference binding does not have any corresponding ASTs.
-
       // Check exception specifications
       // Check exception specifications
       if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
       if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
         return ExprError();
         return ExprError();
 
 
+      // Materialize the temporary into memory.
+      CurInit = new (S.Context) MaterializeTemporaryExpr(CurInit.get(),
+                                     Entity.getType()->isLValueReferenceType());
       break;
       break;
 
 
     case SK_ExtraneousCopyToTemporary:
     case SK_ExtraneousCopyToTemporary:

+ 7 - 0
lib/Sema/TreeTransform.h

@@ -7655,6 +7655,13 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
   return SemaRef.Owned(E);
   return SemaRef.Owned(E);
 }
 }
 
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
+                                                  MaterializeTemporaryExpr *E) {
+  return getDerived().TransformExpr(E->GetTemporaryExpr());
+}
+  
 template<typename Derived>
 template<typename Derived>
 ExprResult
 ExprResult
 TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
 TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {

+ 10 - 0
lib/Serialization/ASTReaderStmt.cpp

@@ -189,6 +189,7 @@ namespace clang {
     void VisitSizeOfPackExpr(SizeOfPackExpr *E);
     void VisitSizeOfPackExpr(SizeOfPackExpr *E);
     void VisitSubstNonTypeTemplateParmPackExpr(
     void VisitSubstNonTypeTemplateParmPackExpr(
                                            SubstNonTypeTemplateParmPackExpr *E);
                                            SubstNonTypeTemplateParmPackExpr *E);
+    void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
     
     
     // CUDA Expressions
     // CUDA Expressions
@@ -1426,6 +1427,11 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
   E->NameLoc = ReadSourceLocation(Record, Idx);
   E->NameLoc = ReadSourceLocation(Record, Idx);
 }
 }
 
 
+void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+  VisitExpr(E);
+  E->Temporary = Reader.ReadSubExpr();
+}
+
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   VisitExpr(E);
   Idx++; // skip ID
   Idx++; // skip ID
@@ -2014,6 +2020,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
       S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
       break;
       break;
         
         
+    case EXPR_MATERIALIZE_TEMPORARY:
+      S = new (Context) MaterializeTemporaryExpr(Empty);
+      break;
+        
     case EXPR_OPAQUE_VALUE: {
     case EXPR_OPAQUE_VALUE: {
       unsigned key = Record[ASTStmtReader::NumExprFields];
       unsigned key = Record[ASTStmtReader::NumExprFields];
       OpaqueValueExpr *&expr = OpaqueValueExprs[key];
       OpaqueValueExpr *&expr = OpaqueValueExprs[key];

+ 7 - 0
lib/Serialization/ASTWriterStmt.cpp

@@ -164,6 +164,7 @@ namespace clang {
     void VisitSizeOfPackExpr(SizeOfPackExpr *E);
     void VisitSizeOfPackExpr(SizeOfPackExpr *E);
     void VisitSubstNonTypeTemplateParmPackExpr(
     void VisitSubstNonTypeTemplateParmPackExpr(
                                            SubstNonTypeTemplateParmPackExpr *E);
                                            SubstNonTypeTemplateParmPackExpr *E);
+    void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
 
 
     // CUDA Expressions
     // CUDA Expressions
@@ -1443,6 +1444,12 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
   Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK;
   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) {
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   VisitExpr(E);
   Record.push_back(Writer.getOpaqueValueID(E));
   Record.push_back(Writer.getOpaqueValueID(E));

+ 19 - 8
lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp

@@ -237,8 +237,11 @@ const GRState *IteratorsChecker::invalidateIterators(const GRState *state,
 const GRState *IteratorsChecker::handleAssign(const GRState *state,
 const GRState *IteratorsChecker::handleAssign(const GRState *state,
     const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
     const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
   // Skip the cast if present.
   // Skip the cast if present.
-  if (isa<ImplicitCastExpr>(lexp))
-    lexp = dyn_cast<ImplicitCastExpr>(lexp)->getSubExpr();
+  if (const MaterializeTemporaryExpr *M 
+                                    = dyn_cast<MaterializeTemporaryExpr>(lexp))
+    lexp = M->GetTemporaryExpr();
+  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp))
+    lexp = ICE->getSubExpr();
   SVal sv = state->getSVal(lexp);
   SVal sv = state->getSVal(lexp);
   const MemRegion *MR = sv.getAsRegion();
   const MemRegion *MR = sv.getAsRegion();
   if (!MR)
   if (!MR)
@@ -260,8 +263,11 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state,
     const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
     const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
   // Assume unknown until we find something definite.
   // Assume unknown until we find something definite.
   state = state->set<IteratorState>(MR, RefState::getUnknown());
   state = state->set<IteratorState>(MR, RefState::getUnknown());
-  if (isa<ImplicitCastExpr>(rexp))
-    rexp = dyn_cast<ImplicitCastExpr>(rexp)->getSubExpr();
+  if (const MaterializeTemporaryExpr *M 
+                                    = dyn_cast<MaterializeTemporaryExpr>(rexp))
+    rexp = M->GetTemporaryExpr();
+  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp))
+    rexp = ICE->getSubExpr();
   // Need to handle three cases: MemberCall, copy, copy with addition.
   // Need to handle three cases: MemberCall, copy, copy with addition.
   if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
   if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
     // Handle MemberCall.
     // Handle MemberCall.
@@ -347,8 +353,10 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
         E = CE->getArg(0);
         E = CE->getArg(0);
     }
     }
   }
   }
-  if (isa<ImplicitCastExpr>(E))
-    E = dyn_cast<ImplicitCastExpr>(E)->getSubExpr();
+  if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
+    E = M->GetTemporaryExpr();
+  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+    E = ICE->getSubExpr();
   // If it isn't one of our types, don't do anything.
   // If it isn't one of our types, don't do anything.
   if (getTemplateKind(E->getType()) != VectorIteratorKind)
   if (getTemplateKind(E->getType()) != VectorIteratorKind)
     return NULL;
     return NULL;
@@ -520,8 +528,11 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
     if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
     if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
       if (CE->getNumArgs() == 1) {
       if (CE->getNumArgs() == 1) {
         const Expr *E = CE->getArg(0);
         const Expr *E = CE->getArg(0);
-        if (isa<ImplicitCastExpr>(E))
-          InitEx = dyn_cast<ImplicitCastExpr>(E)->getSubExpr();
+        if (const MaterializeTemporaryExpr *M
+                                        = dyn_cast<MaterializeTemporaryExpr>(E))
+          E = M->GetTemporaryExpr();
+        if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+          InitEx = ICE->getSubExpr();
         state = handleAssign(state, MR, InitEx,
         state = handleAssign(state, MR, InitEx,
                                   C.getPredecessor()->getLocationContext());
                                   C.getPredecessor()->getLocationContext());
       }
       }

+ 3 - 0
lib/StaticAnalyzer/Core/Environment.cpp

@@ -83,6 +83,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
       case Stmt::CXXBindTemporaryExprClass:
       case Stmt::CXXBindTemporaryExprClass:
         E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
         E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
         continue;
         continue;
+      case Stmt::MaterializeTemporaryExprClass:
+        E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+        continue;
       // Handle all other Stmt* using a lookup.
       // Handle all other Stmt* using a lookup.
       default:
       default:
         break;
         break;

+ 13 - 11
lib/StaticAnalyzer/Core/ExprEngine.cpp

@@ -700,6 +700,16 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
       break;
       break;
     }
     }
 
 
+    case Expr::MaterializeTemporaryExprClass: {
+      const MaterializeTemporaryExpr *Materialize
+                                            = cast<MaterializeTemporaryExpr>(S);
+      if (!Materialize->getType()->isRecordType())
+        CreateCXXTemporaryObject(Materialize->GetTemporaryExpr(), Pred, Dst);
+      else
+        Visit(Materialize->GetTemporaryExpr(), Pred, Dst);
+      break;
+    }
+      
     case Stmt::InitListExprClass:
     case Stmt::InitListExprClass:
       VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
       VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
       break;
       break;
@@ -2306,17 +2316,9 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
   //  time a function is called those values may not be current.
   //  time a function is called those values may not be current.
   ExplodedNodeSet Tmp;
   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);
     Tmp.Add(Pred);
 
 
   ExplodedNodeSet Tmp2;
   ExplodedNodeSet Tmp2;

+ 28 - 0
test/CodeGenCXX/references.cpp

@@ -269,3 +269,31 @@ void h() {
   f(g().b);
   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
+  }
+}

+ 1 - 0
tools/libclang/CXCursor.cpp

@@ -100,6 +100,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
   case Stmt::SEHTryStmtClass:
   case Stmt::SEHTryStmtClass:
   case Stmt::SEHExceptStmtClass:
   case Stmt::SEHExceptStmtClass:
   case Stmt::SEHFinallyStmtClass:
   case Stmt::SEHFinallyStmtClass:
+  case Stmt::MaterializeTemporaryExprClass:
     K = CXCursor_UnexposedStmt;
     K = CXCursor_UnexposedStmt;
     break;
     break;