]> granicus.if.org Git - clang/commitdiff
Introduce a new AST node describing reference binding to temporaries.
authorDouglas Gregor <dgregor@apple.com>
Tue, 21 Jun 2011 17:03:29 +0000 (17:03 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 21 Jun 2011 17:03:29 +0000 (17:03 +0000)
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

27 files changed:
include/clang/AST/Decl.h
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/StmtNodes.td
include/clang/Serialization/ASTBitCodes.h
lib/AST/Decl.cpp
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Analysis/CFG.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaInit.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
lib/StaticAnalyzer/Core/Environment.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CodeGenCXX/references.cpp
tools/libclang/CXCursor.cpp

index 2cc8ec16fff7d59454e87c2f9e6431e680bcdfe4..143915b4b54c263212a49019a419ba57afcbea70 100644 (file)
@@ -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<EvaluatedStmt *>();
     if (!Eval) {
index a97057973745a7bb1e172a0b8ae7c72cedb57c3b..1b1019e5546d40eb5e0597812805236a1b2bdefc 100644 (file)
@@ -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<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
 
index 1a30df6d8b83655eccec7a4547940946150b082d..7cdb0adc65d3b37f991b18d82ed136f22148c6a8 100644 (file)
@@ -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, { })
index f503950c20e9773980cd4677c41f0cb088c552bb..c07953eecae9bbcff0d422378e189234bc13af9e 100644 (file)
@@ -121,6 +121,7 @@ def CXXNoexceptExpr : DStmt<Expr>;
 def PackExpansionExpr : DStmt<Expr>;
 def SizeOfPackExpr : DStmt<Expr>;
 def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
+def MaterializeTemporaryExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
index 12f701e4605d5ff0d6b86c63ac478ee2f34edef7..15fe3c61ae3994aa31970c784e39c4740e3583e3 100644 (file)
@@ -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      
 
index c2abe1a5a90d5a9c322daa47439e06701275f570..cdec049cb12ac660995cd2feb13a94505ff19170 100644 (file)
@@ -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<ExprWithCleanups>(E))
+    E = Cleanups->getSubExpr();
+  
+  return isa<MaterializeTemporaryExpr>(E);
+}
+
 VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return cast<VarDecl>(MSI->getInstantiatedFrom());
index 2f303da7b5a69cc993755125d064c991136716e8..31972bdd23e044692a697076e1e8f52557340531 100644 (file)
@@ -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();
index 1a1fa91a40a5805d9eec158995fcdc89c6a4a7e6..2d824ce8fd77b25035893f495513d24ea74bd33c 100644 (file)
@@ -341,6 +341,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
       
   case Expr::PackExpansionExprClass:
     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");
index 432ffee08de55e6b64ddd0243395b88a2d6e82df..7d2ea13d0a74c066765a9089b3b56b10eb499164 100644 (file)
@@ -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:
index 5f0b2a6eff82b5d8f2503312256a48c461ccc39c..92e166a34a33e3b47b34f6ff220a4e646e1fa74b 100644 (file)
@@ -2591,6 +2591,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
     }
     break;
   }
+      
+  case Expr::MaterializeTemporaryExprClass: {
+    mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
+    break;
+  }
   }
 }
 
index d6a67b13ef7bf4e5279feba84d0d7a6031c37319..f8edaf7ccf226d9bf26cf4c8aec636f998a32f1e 100644 (file)
@@ -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) {
index 52b5a103e792d76024e989b5c1175f8e17522d39..7c1aa9c6f7e8ddfaa51f633516c159957fd1d298 100644 (file)
@@ -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);  
 }
index 3e540203eaa07f5f2654ee959de2a58d93a0bd14..f231c147f11ee4f1f834f411ce77321626d8eb5b 100644 (file)
@@ -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<ParenExpr>(E)->getSubExpr();
       goto tryAgain;
+      
+    case Stmt::MaterializeTemporaryExprClass:
+      E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+      goto tryAgain;
   }
 }
 
index 20ccdb7f9cb8c58e61ee26f5b17ac20d687d4d10..d5c18eba70ae2ee731275e1d34fbf32de2f15bbe 100644 (file)
@@ -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<MaterializeTemporaryExpr>(E))
+    E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+
   if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
     E = DAE->getExpr();
   
@@ -667,6 +671,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
   case Expr::CXXConstCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
     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);
 }
 
+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()) {
index b1ac731f21342d589634437322f83497e1badea5..1cd196a0e48aef9403a760e198a3b9e0ed35affd 100644 (file)
@@ -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));
 }
index 5184f475375199c43fae2df72f76ad384fe98f0e..e88c28737c61b198a8cdcba3d0fe6cd4ff30106f 100644 (file)
@@ -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() &&
index f34a70c5d9e7c870df60a9f8efac8aae5b2d91c7..e72d6ced921ebea08712004a0fc6ea342f2d3a9b 100644 (file)
@@ -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,
index 54900e0cf15c095a1979b725317be498765ac2e9..1b9fd7769bd4dfbec5443e939e53fce35960df3c 100644 (file)
@@ -2205,6 +2205,14 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
         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.
   default:
     return NULL;
@@ -2306,6 +2314,14 @@ do {
     return EvalVal(M->getBase(), refVars);
   }
 
+  case Stmt::MaterializeTemporaryExprClass:
+    if (Expr *Result = EvalVal(
+                          cast<MaterializeTemporaryExpr>(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++.
index 5bdadc6166b11560719caf4e9b3cc539a8202287..3231455f5a5c07712eee42b5c8353cd1270e48fb 100644 (file)
@@ -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:
index 121ff00628c2b4535cf996d9c18e6eda543b30ac..b8060277ed349068c3500a7f8c5cb2522531bfa9 100644 (file)
@@ -7655,6 +7655,13 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
   return SemaRef.Owned(E);
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
+                                                  MaterializeTemporaryExpr *E) {
+  return getDerived().TransformExpr(E->GetTemporaryExpr());
+}
+  
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
index 0af3546223ce352a79e519e267a60e91165e9125..f6c27d410685af4c98b73d40d9c65171d4c1fda0 100644 (file)
@@ -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];
index c6d182d425450b9b979717fecaeaa36e3edd828d..b66fdfa558d8689f7439256d5646b9b3fc7e91b6 100644 (file)
@@ -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));
index e4e5f54770b31799e9f840a775729fc6ed7d75c4..de6da4f8c3776381c0128cb7ac63cf21fc7a82dd 100644 (file)
@@ -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<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);
   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<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.
   if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
     // Handle MemberCall.
@@ -347,8 +353,10 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
         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 (getTemplateKind(E->getType()) != VectorIteratorKind)
     return NULL;
@@ -520,8 +528,11 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
     if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
       if (CE->getNumArgs() == 1) {
         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,
                                   C.getPredecessor()->getLocationContext());
       }
index 48f126bfd8636dd476f8e13948e7bea1f2930f5c..3961c7b952591483bb843c99574464f565dc27f5 100644 (file)
@@ -83,6 +83,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
       case Stmt::CXXBindTemporaryExprClass:
         E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
         continue;
+      case Stmt::MaterializeTemporaryExprClass:
+        E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+        continue;
       // Handle all other Stmt* using a lookup.
       default:
         break;
index 21efbac6996bfdb61781a17d6081510b7c1edf33..4aa5e350bc1b3e308ba9b8aa5521eeed2940a83d 100644 (file)
@@ -700,6 +700,16 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
       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:
       VisitInitListExpr(cast<InitListExpr>(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;
index 25bc8d801790290c1d552d614e281dc5cf231755..d53815ded71474a02f224dfadd1b69054a3c7867 100644 (file)
@@ -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
+  }
+}
index 35134513419270ca4558329122063ccdcaf85241..f2ee2a9225976c570d0dfab271f9eeaf6e11dc2b 100644 (file)
@@ -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;