On Tue, Jun 4, 2013 at 6:57 PM, Jordan Rose <span dir="ltr"><<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
When we get around to modeling non-trivial temporaries in the static analyzer, this will probably be very, very useful. Thanks for doing all this.</blockquote><div><br></div><div>:-) I've still not got to the miscompile I originally set out to fix here...</div>
<div><br></div><div><a href="http://www.bcdb.com/cartoon_video/28426-Yak_Shaving_Day.html">http://www.bcdb.com/cartoon_video/28426-Yak_Shaving_Day.html</a></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5">
On Jun 4, 2013, at 17:46 , Richard Smith <<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>> wrote:<br>
<br>
> Author: rsmith<br>
> Date: Tue Jun  4 19:46:14 2013<br>
> New Revision: 183283<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=183283&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=183283&view=rev</a><br>
> Log:<br>
> Model temporary lifetime-extension explicitly in the AST. Use this model to<br>
> handle temporaries which have been lifetime-extended to static storage duration<br>
> within constant expressions. This correctly handles nested lifetime extension<br>
> (through reference members of aggregates in aggregate initializers) but<br>
> non-constant-expression emission hasn't yet been updated to do the same.<br>
><br>
> Modified:<br>
>    cfe/trunk/include/clang/AST/ASTContext.h<br>
>    cfe/trunk/include/clang/AST/Decl.h<br>
>    cfe/trunk/include/clang/AST/ExprCXX.h<br>
>    cfe/trunk/include/clang/AST/Stmt.h<br>
>    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td<br>
>    cfe/trunk/include/clang/Basic/Specifiers.h<br>
>    cfe/trunk/include/clang/Sema/Initialization.h<br>
>    cfe/trunk/lib/AST/ASTContext.cpp<br>
>    cfe/trunk/lib/AST/ASTDumper.cpp<br>
>    cfe/trunk/lib/AST/ExprConstant.cpp<br>
>    cfe/trunk/lib/CodeGen/CGExprConstant.cpp<br>
>    cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
>    cfe/trunk/lib/CodeGen/CodeGenModule.h<br>
>    cfe/trunk/lib/Sema/SemaExpr.cpp<br>
>    cfe/trunk/lib/Sema/SemaInit.cpp<br>
>    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp<br>
>    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp<br>
>    cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp<br>
>    cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp<br>
>    cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp<br>
>    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp<br>
>    cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp<br>
><br>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)<br>
> +++ cfe/trunk/include/clang/AST/ASTContext.h Tue Jun  4 19:46:14 2013<br>
> @@ -55,6 +55,7 @@ namespace clang {<br>
>   class ExternalASTSource;<br>
>   class ASTMutationListener;<br>
>   class IdentifierTable;<br>
> +  class MaterializeTemporaryExpr;<br>
>   class SelectorTable;<br>
>   class TargetInfo;<br>
>   class CXXABI;<br>
> @@ -163,6 +164,11 @@ class ASTContext : public RefCountedBase<br>
>   llvm::DenseMap<const FunctionDecl*, FunctionDecl*><br>
>     ClassScopeSpecializationPattern;<br>
><br>
> +  /// \brief Mapping from materialized temporaries with static storage duration<br>
> +  /// that appear in constant initializers to their evaluated values.<br>
> +  llvm::DenseMap<const MaterializeTemporaryExpr*, APValue><br>
> +    MaterializedTemporaryValues;<br>
> +<br>
>   /// \brief Representation of a "canonical" template template parameter that<br>
>   /// is used in canonical template names.<br>
>   class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {<br>
> @@ -2117,7 +2123,12 @@ public:<br>
>   /// \brief Used by ParmVarDecl to retrieve on the side the<br>
>   /// index of the parameter when it exceeds the size of the normal bitfield.<br>
>   unsigned getParameterIndex(const ParmVarDecl *D) const;<br>
> -<br>
> +<br>
> +  /// \brief Get the storage for the constant value of a materialized temporary<br>
> +  /// of static storage duration.<br>
> +  APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,<br>
> +                                         bool MayCreate);<br>
> +<br>
>   //===--------------------------------------------------------------------===//<br>
>   //                    Statistics<br>
>   //===--------------------------------------------------------------------===//<br>
><br>
> Modified: cfe/trunk/include/clang/AST/Decl.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/Decl.h (original)<br>
> +++ cfe/trunk/include/clang/AST/Decl.h Tue Jun  4 19:46:14 2013<br>
> @@ -811,7 +811,7 @@ public:<br>
>   bool hasLocalStorage() const {<br>
>     if (getStorageClass() == SC_None)<br>
>       // Second check is for C++11 [dcl.stc]p4.<br>
> -      return !isFileVarDecl() && getTSCSpec() != TSCS_thread_local;<br>
> +      return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;<br>
><br>
>     // Return true for:  Auto, Register.<br>
>     // Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.<br>
> @@ -840,6 +840,12 @@ public:<br>
>   ///  as static variables declared within a function.<br>
>   bool hasGlobalStorage() const { return !hasLocalStorage(); }<br>
><br>
> +  /// \brief Get the storage duration of this variable, per C++ [basid.stc].<br>
> +  StorageDuration getStorageDuration() const {<br>
> +    return hasLocalStorage() ? SD_Automatic :<br>
> +           getTSCSpec() ? SD_Thread : SD_Static;<br>
> +  }<br>
> +<br>
>   /// Compute the language linkage.<br>
>   LanguageLinkage getLanguageLinkage() const;<br>
><br>
><br>
> Modified: cfe/trunk/include/clang/AST/ExprCXX.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/ExprCXX.h (original)<br>
> +++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Jun  4 19:46:14 2013<br>
> @@ -3824,30 +3824,60 @@ public:<br>
> /// binds to the temporary. \c MaterializeTemporaryExprs are always glvalues<br>
> /// (either an lvalue or an xvalue, depending on the kind of reference binding<br>
> /// to it), maintaining the invariant that references always bind to glvalues.<br>
> +///<br>
> +/// Reference binding and copy-elision can both extend the lifetime of a<br>
> +/// temporary. When either happens, the expression will also track the<br>
> +/// declaration which is responsible for the lifetime extension.<br>
> class MaterializeTemporaryExpr : public Expr {<br>
> +public:<br>
>   /// \brief The temporary-generating expression whose value will be<br>
>   /// materialized.<br>
>   Stmt *Temporary;<br>
><br>
> +  /// \brief The declaration which lifetime-extended this reference, if any.<br>
> +  /// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.<br>
> +  const ValueDecl *ExtendingDecl;<br>
> +<br>
>   friend class ASTStmtReader;<br>
>   friend class ASTStmtWriter;<br>
><br>
> public:<br>
>   MaterializeTemporaryExpr(QualType T, Expr *Temporary,<br>
> -                           bool BoundToLvalueReference)<br>
> +                           bool BoundToLvalueReference,<br>
> +                           const ValueDecl *ExtendedBy)<br>
>     : Expr(MaterializeTemporaryExprClass, T,<br>
>            BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,<br>
>            Temporary->isTypeDependent(), Temporary->isValueDependent(),<br>
>            Temporary->isInstantiationDependent(),<br>
>            Temporary->containsUnexpandedParameterPack()),<br>
> -      Temporary(Temporary) { }<br>
> +      Temporary(Temporary), ExtendingDecl(ExtendedBy) {<br>
> +  }<br>
><br>
>   MaterializeTemporaryExpr(EmptyShell Empty)<br>
>     : Expr(MaterializeTemporaryExprClass, Empty) { }<br>
><br>
>   /// \brief Retrieve the temporary-generating subexpression whose value will<br>
>   /// be materialized into a glvalue.<br>
> -  Expr *GetTemporaryExpr() const { return reinterpret_cast<Expr *>(Temporary); }<br>
> +  Expr *GetTemporaryExpr() const { return static_cast<Expr *>(Temporary); }<br>
> +<br>
> +  /// \brief Retrieve the storage duration for the materialized temporary.<br>
> +  StorageDuration getStorageDuration() const {<br>
> +    if (!ExtendingDecl)<br>
> +      return SD_FullExpression;<br>
> +    // FIXME: This is not necessarily correct for a temporary materialized<br>
> +    // within a default initializer.<br>
> +    if (isa<FieldDecl>(ExtendingDecl))<br>
> +      return SD_Automatic;<br>
> +    return cast<VarDecl>(ExtendingDecl)->getStorageDuration();<br>
> +  }<br>
> +<br>
> +  /// \brief Get the declaration which triggered the lifetime-extension of this<br>
> +  /// temporary, if any.<br>
> +  const ValueDecl *getExtendingDecl() const { return ExtendingDecl; }<br>
> +<br>
> +  void setExtendingDecl(const ValueDecl *ExtendedBy) {<br>
> +    ExtendingDecl = ExtendedBy;<br>
> +  }<br>
><br>
>   /// \brief Determine whether this materialized temporary is bound to an<br>
>   /// lvalue reference; otherwise, it's bound to an rvalue reference.<br>
><br>
> Modified: cfe/trunk/include/clang/AST/Stmt.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/Stmt.h (original)<br>
> +++ cfe/trunk/include/clang/AST/Stmt.h Tue Jun  4 19:46:14 2013<br>
> @@ -289,7 +289,7 @@ protected:<br>
>     /// \brief The number of arguments to this type trait.<br>
>     unsigned NumArgs : 32 - 8 - 1 - NumExprBits;<br>
>   };<br>
> -<br>
> +<br>
>   union {<br>
>     // FIXME: this is wasteful on 64-bit platforms.<br>
>     void *Aligner;<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Tue Jun  4 19:46:14 2013<br>
> @@ -117,6 +117,10 @@ def note_constexpr_access_inactive_union<br>
>   "%select{read of|assignment to|increment of|decrement of}0 "<br>
>   "member %1 of union with %select{active member %3|no active member}2 "<br>
>   "is not allowed in a constant expression">;<br>
> +def note_constexpr_access_static_temporary : Note<<br>
> +  "%select{read of|assignment to|increment of|decrement of}0 temporary "<br>
> +  "is not allowed in a constant expression outside the expression that "<br>
> +  "created the temporary">;<br>
> def note_constexpr_modify_global : Note<<br>
>   "a constant expression cannot modify an object that is visible outside "<br>
>   "that expression">;<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/Specifiers.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/Specifiers.h (original)<br>
> +++ cfe/trunk/include/clang/Basic/Specifiers.h Tue Jun  4 19:46:14 2013<br>
> @@ -212,6 +212,14 @@ namespace clang {<br>
>     CC_IntelOclBicc // __attribute__((intel_ocl_bicc))<br>
>   };<br>
><br>
> +  /// \brief The storage duration for an object (per C++ [basic.stc]).<br>
> +  enum StorageDuration {<br>
> +    SD_FullExpression, ///< Full-expression storage duration (for temporaries).<br>
> +    SD_Automatic,      ///< Automatic storage duration (most local variables).<br>
> +    SD_Thread,         ///< Thread storage duration.<br>
> +    SD_Static,         ///< Static storage duration.<br>
> +    SD_Dynamic         ///< Dynamic storage duration.<br>
> +  };<br>
> } // end namespace clang<br>
><br>
> #endif // LLVM_CLANG_BASIC_SPECIFIERS_H<br>
><br>
> Modified: cfe/trunk/include/clang/Sema/Initialization.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/Initialization.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/Initialization.h Tue Jun  4 19:46:14 2013<br>
> @@ -384,6 +384,13 @@ public:<br>
>     assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");<br>
>     return SourceLocation::getFromRawEncoding(Capture.Location);<br>
>   }<br>
> +<br>
> +  /// Dump a representation of the initialized entity to standard error,<br>
> +  /// for debugging purposes.<br>
> +  void dump() const;<br>
> +<br>
> +private:<br>
> +  unsigned dumpImpl(raw_ostream &OS) const;<br>
> };<br>
><br>
> /// \brief Describes the kind of initialization being performed, along with<br>
><br>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>
> +++ cfe/trunk/lib/AST/ASTContext.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -8029,6 +8029,19 @@ unsigned ASTContext::getParameterIndex(c<br>
>   return I->second;<br>
> }<br>
><br>
> +APValue *<br>
> +ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,<br>
> +                                          bool MayCreate) {<br>
> +  assert(E && E->getStorageDuration() == SD_Static &&<br>
> +         "don't need to cache the computed value for this temporary");<br>
> +  if (MayCreate)<br>
> +    return &MaterializedTemporaryValues[E];<br>
> +<br>
> +  llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I =<br>
> +      MaterializedTemporaryValues.find(E);<br>
> +  return I == MaterializedTemporaryValues.end() ? 0 : &I->second;<br>
> +}<br>
> +<br>
> bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {<br>
>   const llvm::Triple &T = getTargetInfo().getTriple();<br>
>   if (!T.isOSDarwin())<br>
><br>
> Modified: cfe/trunk/lib/AST/ASTDumper.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/AST/ASTDumper.cpp (original)<br>
> +++ cfe/trunk/lib/AST/ASTDumper.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -274,6 +274,7 @@ namespace  {<br>
>     void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);<br>
>     void VisitCXXConstructExpr(const CXXConstructExpr *Node);<br>
>     void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);<br>
> +    void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);<br>
>     void VisitExprWithCleanups(const ExprWithCleanups *Node);<br>
>     void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);<br>
>     void dumpCXXTemporary(const CXXTemporary *Temporary);<br>
> @@ -1682,6 +1683,15 @@ void ASTDumper::VisitCXXBindTemporaryExp<br>
>   dumpCXXTemporary(Node->getTemporary());<br>
> }<br>
><br>
> +void<br>
> +ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {<br>
> +  VisitExpr(Node);<br>
> +  if (const ValueDecl *VD = Node->getExtendingDecl()) {<br>
> +    OS << " extended by ";<br>
> +    dumpBareDeclRef(VD);<br>
> +  }<br>
> +}<br>
> +<br>
> void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {<br>
>   VisitExpr(Node);<br>
>   for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)<br>
><br>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br>
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -1001,6 +1001,10 @@ static bool IsGlobalLValue(APValue::LVal<br>
>     const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);<br>
>     return CLE->isFileScope() && CLE->isLValue();<br>
>   }<br>
> +  case Expr::MaterializeTemporaryExprClass:<br>
> +    // A materialized temporary might have been lifetime-extended to static<br>
> +    // storage duration.<br>
> +    return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static;<br>
>   // A string literal has static storage duration.<br>
>   case Expr::StringLiteralClass:<br>
>   case Expr::PredefinedExprClass:<br>
> @@ -1182,7 +1186,10 @@ const ValueDecl *GetLValueBaseDecl(const<br>
> }<br>
><br>
> static bool IsLiteralLValue(const LValue &Value) {<br>
> -  return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;<br>
> +  if (Value.CallIndex)<br>
> +    return false;<br>
> +  const Expr *E = Value.Base.dyn_cast<const Expr*>();<br>
> +  return E && !isa<MaterializeTemporaryExpr>(E);<br>
> }<br>
><br>
> static bool IsWeakLValue(const LValue &Value) {<br>
> @@ -2279,11 +2286,44 @@ CompleteObject findCompleteObject(EvalIn<br>
>     const Expr *Base = LVal.Base.dyn_cast<const Expr*>();<br>
><br>
>     if (!Frame) {<br>
> -      Info.Diag(E);<br>
> -      return CompleteObject();<br>
> -    }<br>
> +      if (const MaterializeTemporaryExpr *MTE =<br>
> +              dyn_cast<MaterializeTemporaryExpr>(Base)) {<br>
> +        assert(MTE->getStorageDuration() == SD_Static &&<br>
> +               "should have a frame for a non-global materialized temporary");<br>
> +<br>
> +        // Per C++1y [expr.const]p2:<br>
> +        //  an lvalue-to-rvalue conversion [is not allowed unless it applies to]<br>
> +        //   - a [...] glvalue of integral or enumeration type that refers to<br>
> +        //     a non-volatile const object [...]<br>
> +        //   [...]<br>
> +        //   - a [...] glvalue of literal type that refers to a non-volatile<br>
> +        //     object whose lifetime began within the evaluation of e.<br>
> +        //<br>
> +        // C++11 misses the 'began within the evaluation of e' check and<br>
> +        // instead allows all temporaries, including things like:<br>
> +        //   int &&r = 1;<br>
> +        //   int x = ++r;<br>
> +        //   constexpr int k = r;<br>
> +        // Therefore we use the C++1y rules in C++11 too.<br>
> +        const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();<br>
> +        const ValueDecl *ED = MTE->getExtendingDecl();<br>
> +        if (!(BaseType.isConstQualified() &&<br>
> +              BaseType->isIntegralOrEnumerationType()) &&<br>
> +            !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {<br>
> +          Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK;<br>
> +          Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);<br>
> +          return CompleteObject();<br>
> +        }<br>
><br>
> -    BaseVal = &Frame->Temporaries[Base];<br>
> +        BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);<br>
> +        assert(BaseVal && "got reference to unevaluated temporary");<br>
> +      } else {<br>
> +        Info.Diag(E);<br>
> +        return CompleteObject();<br>
> +      }<br>
> +    } else {<br>
> +      BaseVal = &Frame->Temporaries[Base];<br>
> +    }<br>
><br>
>     // Volatile temporary objects cannot be accessed in constant expressions.<br>
>     if (BaseType.isVolatileQualified()) {<br>
> @@ -3940,6 +3980,8 @@ public:<br>
> //  * Any Expr, with a CallIndex indicating the function in which the temporary<br>
> //    was evaluated, for cases where the MaterializeTemporaryExpr is missing<br>
> //    from the AST (FIXME).<br>
> +//  * A MaterializeTemporaryExpr that has static storage duration, with no<br>
> +//    CallIndex, for a lifetime-extended temporary.<br>
> // plus an offset in bytes.<br>
> //===----------------------------------------------------------------------===//<br>
> namespace {<br>
> @@ -4045,9 +4087,19 @@ bool LValueExprEvaluator::VisitMateriali<br>
>     if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))<br>
>       return false;<br>
><br>
> +  // A materialized temporary with static storage duration can appear within the<br>
> +  // result of a constant expression evaluation, so we need to preserve its<br>
> +  // value for use outside this evaluation.<br>
> +  APValue *Value;<br>
> +  if (E->getStorageDuration() == SD_Static) {<br>
> +    Value = Info.Ctx.getMaterializedTemporaryValue(E, true);<br>
> +    Result.set(E);<br>
> +  } else {<br>
> +    Value = &Info.CurrentCall->Temporaries[E];<br>
> +    Result.set(E, Info.CurrentCall->Index);<br>
> +  }<br>
> +<br>
>   // Materialize the temporary itself.<br>
> -  APValue *Value = &Info.CurrentCall->Temporaries[E];<br>
> -  Result.set(E, Info.CurrentCall->Index);<br>
>   if (!EvaluateInPlace(*Value, Info, Result, Inner))<br>
>     return false;<br>
><br>
> @@ -7608,10 +7660,10 @@ void Expr::EvaluateForOverflow(const AST<br>
>   }<br>
> }<br>
><br>
> - bool Expr::EvalResult::isGlobalLValue() const {<br>
> -   assert(Val.isLValue());<br>
> -   return IsGlobalLValue(Val.getLValueBase());<br>
> - }<br>
> +bool Expr::EvalResult::isGlobalLValue() const {<br>
> +  assert(Val.isLValue());<br>
> +  return IsGlobalLValue(Val.getLValueBase());<br>
> +}<br>
><br>
><br>
> /// isIntegerConstantExpr - this recursive routine will test if an expression is<br>
><br>
> Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)<br>
> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -1003,6 +1003,15 @@ public:<br>
>     case Expr::CXXUuidofExprClass: {<br>
>       return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E));<br>
>     }<br>
> +    case Expr::MaterializeTemporaryExprClass: {<br>
> +      MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);<br>
> +      assert(MTE->getStorageDuration() == SD_Static);<br>
> +      SmallVector<const Expr *, 2> CommaLHSs;<br>
> +      SmallVector<SubobjectAdjustment, 2> Adjustments;<br>
> +      const Expr *Inner = MTE->GetTemporaryExpr()<br>
> +          ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);<br>
> +      return CGM.GetAddrOfGlobalTemporary(MTE, Inner);<br>
> +    }<br>
>     }<br>
><br>
>     return 0;<br>
><br>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)<br>
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -2735,6 +2735,63 @@ llvm::Constant *CodeGenModule::GetAddrOf<br>
>   return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment);<br>
> }<br>
><br>
> +llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(<br>
> +    const MaterializeTemporaryExpr *E, const Expr *Inner) {<br>
> +  assert((E->getStorageDuration() == SD_Static ||<br>
> +          E->getStorageDuration() == SD_Thread) && "not a global temporary");<br>
> +  const VarDecl *VD = cast<VarDecl>(E->getExtendingDecl());<br>
> +<br>
> +  // If we're not materializing a subobject of the temporary, keep the<br>
> +  // cv-qualifiers from the type of the MaterializeTemporaryExpr.<br>
> +  if (Inner == E->GetTemporaryExpr())<br>
> +    Inner = E;<br>
> +<br>
> +  llvm::Constant *&Slot = MaterializedGlobalTemporaryMap[E];<br>
> +  if (Slot)<br>
> +    return Slot;<br>
> +<br>
> +  // FIXME: If an externally-visible declaration extends multiple temporaries,<br>
> +  // we need to give each temporary the same name in every translation unit (and<br>
> +  // we also need to make the temporaries externally-visible).<br>
> +  SmallString<256> Name;<br>
> +  llvm::raw_svector_ostream Out(Name);<br>
> +  getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);<br>
> +  Out.flush();<br>
> +<br>
> +  llvm::Constant *InitialValue = 0;<br>
> +  APValue *Value = 0;<br>
> +  if (E->getStorageDuration() == SD_Static) {<br>
> +    // We might have a constant initializer for this temporary.<br>
> +    Value = getContext().getMaterializedTemporaryValue(E, false);<br>
> +    if (Value && Value->isUninit())<br>
> +      Value = 0;<br>
> +  }<br>
> +<br>
> +  bool Constant;<br>
> +  if (Value) {<br>
> +    // The temporary has a constant initializer, use it.<br>
> +    InitialValue = EmitConstantValue(*Value, Inner->getType(), 0);<br>
> +    Constant = isTypeConstant(Inner->getType(), /*ExcludeCtor*/Value);<br>
> +  } else {<br>
> +    // No constant initializer, the initialization will be provided when we<br>
> +    // initialize the declaration which performed lifetime extension.<br>
> +    InitialValue = EmitNullConstant(Inner->getType());<br>
> +    Constant = false;<br>
> +  }<br>
> +<br>
> +  // Create a global variable for this lifetime-extended temporary.<br>
> +  llvm::GlobalVariable *GV =<br>
> +    new llvm::GlobalVariable(getModule(), InitialValue->getType(), Constant,<br>
> +                             llvm::GlobalValue::PrivateLinkage, InitialValue,<br>
> +                             Name.c_str());<br>
> +  GV->setAlignment(<br>
> +      getContext().getTypeAlignInChars(Inner->getType()).getQuantity());<br>
> +  if (VD->getTLSKind())<br>
> +    setTLSMode(GV, *VD);<br>
> +  Slot = GV;<br>
> +  return GV;<br>
> +}<br>
> +<br>
> /// EmitObjCPropertyImplementations - Emit information for synthesized<br>
> /// properties for an implementation.<br>
> void CodeGenModule::EmitObjCPropertyImplementations(const<br>
><br>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)<br>
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Jun  4 19:46:14 2013<br>
> @@ -307,7 +307,8 @@ class CodeGenModule : public CodeGenType<br>
>   llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;<br>
>   llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;<br>
>   llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;<br>
> -<br>
> +  llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;<br>
> +<br>
>   llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;<br>
>   llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;<br>
><br>
> @@ -731,7 +732,12 @@ public:<br>
>   /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global<br>
>   /// variable for the given file-scope compound literal expression.<br>
>   llvm::Constant *GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);<br>
> -<br>
> +<br>
> +  /// \brief Returns a pointer to a global variable representing a temporary<br>
> +  /// with static or thread storage duration.<br>
> +  llvm::Constant *GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E,<br>
> +                                           const Expr *Inner);<br>
> +<br>
>   /// \brief Retrieve the record type that describes the state of an<br>
>   /// Objective-C fast enumeration loop (for..in).<br>
>   QualType getObjCFastEnumerationStateType();<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -8353,7 +8353,7 @@ static QualType CheckAddressOfOperand(Se<br>
>       return QualType();<br>
>     // Materialize the temporary as an lvalue so that we can take its address.<br>
>     OrigOp = op = new (S.Context)<br>
> -        MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true);<br>
> +        MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true, 0);<br>
>   } else if (isa<ObjCSelectorExpr>(op)) {<br>
>     return S.Context.getPointerType(op->getType());<br>
>   } else if (lval == Expr::LV_MemberFunction) {<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaInit.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -2502,6 +2502,46 @@ bool InitializedEntity::allowsNRVO() con<br>
>   return false;<br>
> }<br>
><br>
> +unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {<br>
> +  unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;<br>
> +  for (unsigned I = 0; I != Depth; ++I)<br>
> +    OS << "`-";<br>
> +<br>
> +  switch (getKind()) {<br>
> +  case EK_Variable: OS << "Variable"; break;<br>
> +  case EK_Parameter: OS << "Parameter"; break;<br>
> +  case EK_Result: OS << "Result"; break;<br>
> +  case EK_Exception: OS << "Exception"; break;<br>
> +  case EK_Member: OS << "Member"; break;<br>
> +  case EK_New: OS << "New"; break;<br>
> +  case EK_Temporary: OS << "Temporary"; break;<br>
> +  case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;<br>
> +  case EK_Base: OS << "Base"; break;<br>
> +  case EK_Delegating: OS << "Delegating"; break;<br>
> +  case EK_ArrayElement: OS << "ArrayElement " << Index; break;<br>
> +  case EK_VectorElement: OS << "VectorElement " << Index; break;<br>
> +  case EK_ComplexElement: OS << "ComplexElement " << Index; break;<br>
> +  case EK_BlockElement: OS << "Block"; break;<br>
> +  case EK_LambdaCapture:<br>
> +    OS << "LambdaCapture ";<br>
> +    getCapturedVar()->printName(OS);<br>
> +    break;<br>
> +  }<br>
> +<br>
> +  if (Decl *D = getDecl()) {<br>
> +    OS << " ";<br>
> +    cast<NamedDecl>(D)->printQualifiedName(OS);<br>
> +  }<br>
> +<br>
> +  OS << " '" << getType().getAsString() << "'\n";<br>
> +<br>
> +  return Depth + 1;<br>
> +}<br>
> +<br>
> +void InitializedEntity::dump() const {<br>
> +  dumpImpl(llvm::errs());<br>
> +}<br>
> +<br>
> //===----------------------------------------------------------------------===//<br>
> // Initialization sequence<br>
> //===----------------------------------------------------------------------===//<br>
> @@ -5089,6 +5129,143 @@ InitializedEntityOutlivesFullExpression(<br>
>   llvm_unreachable("unknown entity kind");<br>
> }<br>
><br>
> +/// Determine the declaration which an initialized entity ultimately refers to,<br>
> +/// for the purpose of lifetime-extending a temporary bound to a reference in<br>
> +/// the initialization of \p Entity.<br>
> +static const ValueDecl *<br>
> +getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,<br>
> +                                     const ValueDecl *FallbackDecl = 0) {<br>
> +  // C++11 [class.temporary]p5:<br>
> +  switch (Entity.getKind()) {<br>
> +  case InitializedEntity::EK_Variable:<br>
> +    //   The temporary [...] persists for the lifetime of the reference<br>
> +    return Entity.getDecl();<br>
> +<br>
> +  case InitializedEntity::EK_Member:<br>
> +    // For subobjects, we look at the complete object.<br>
> +    if (Entity.getParent())<br>
> +      return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),<br>
> +                                                  Entity.getDecl());<br>
> +<br>
> +    //   except:<br>
> +    //   -- A temporary bound to a reference member in a constructor's<br>
> +    //      ctor-initializer persists until the constructor exits.<br>
> +    return Entity.getDecl();<br>
> +<br>
> +  case InitializedEntity::EK_Parameter:<br>
> +    //   -- A temporary bound to a reference parameter in a function call<br>
> +    //      persists until the completion of the full-expression containing<br>
> +    //      the call.<br>
> +  case InitializedEntity::EK_Result:<br>
> +    //   -- The lifetime of a temporary bound to the returned value in a<br>
> +    //      function return statement is not extended; the temporary is<br>
> +    //      destroyed at the end of the full-expression in the return statement.<br>
> +  case InitializedEntity::EK_New:<br>
> +    //   -- A temporary bound to a reference in a new-initializer persists<br>
> +    //      until the completion of the full-expression containing the<br>
> +    //      new-initializer.<br>
> +    return 0;<br>
> +<br>
> +  case InitializedEntity::EK_Temporary:<br>
> +  case InitializedEntity::EK_CompoundLiteralInit:<br>
> +    // We don't yet know the storage duration of the surrounding temporary.<br>
> +    // Assume it's got full-expression duration for now, it will patch up our<br>
> +    // storage duration if that's not correct.<br>
> +    return 0;<br>
> +<br>
> +  case InitializedEntity::EK_ArrayElement:<br>
> +    // For subobjects, we look at the complete object.<br>
> +    return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),<br>
> +                                                FallbackDecl);<br>
> +<br>
> +  case InitializedEntity::EK_Base:<br>
> +  case InitializedEntity::EK_Delegating:<br>
> +    // We can reach this case for aggregate initialization in a constructor:<br>
> +    //   struct A { int &&r; };<br>
> +    //   struct B : A { B() : A{0} {} };<br>
> +    // In this case, use the innermost field decl as the context.<br>
> +    return FallbackDecl;<br>
> +<br>
> +  case InitializedEntity::EK_BlockElement:<br>
> +  case InitializedEntity::EK_LambdaCapture:<br>
> +  case InitializedEntity::EK_Exception:<br>
> +  case InitializedEntity::EK_VectorElement:<br>
> +  case InitializedEntity::EK_ComplexElement:<br>
> +    llvm_unreachable("should not materialize a temporary to initialize this");<br>
> +  }<br>
> +}<br>
> +<br>
> +static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD);<br>
> +<br>
> +/// Update a glvalue expression that is used as the initializer of a reference<br>
> +/// to note that its lifetime is extended.<br>
> +static void performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {<br>
> +  if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {<br>
> +    if (ILE->getNumInits() == 1 && ILE->isGLValue()) {<br>
> +      // This is just redundant braces around an initializer. Step over it.<br>
> +      Init = ILE->getInit(0);<br>
> +    }<br>
> +  }<br>
> +<br>
> +  if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {<br>
> +    // Update the storage duration of the materialized temporary.<br>
> +    // FIXME: Rebuild the expression instead of mutating it.<br>
> +    ME->setExtendingDecl(ExtendingD);<br>
> +    performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD);<br>
> +  }<br>
> +}<br>
> +<br>
> +/// Update a prvalue expression that is going to be materialized as a<br>
> +/// lifetime-extended temporary.<br>
> +static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {<br>
> +  // Dig out the expression which constructs the extended temporary.<br>
> +  SmallVector<const Expr *, 2> CommaLHSs;<br>
> +  SmallVector<SubobjectAdjustment, 2> Adjustments;<br>
> +  Init = const_cast<Expr *>(<br>
> +      Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));<br>
> +<br>
> +  if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {<br>
> +    if (ILE->initializesStdInitializerList()) {<br>
> +      // FIXME: If this is an InitListExpr which creates a std::initializer_list<br>
> +      //        object, we also need to lifetime-extend the underlying array<br>
> +      //        itself. Fix the representation to explicitly materialize an<br>
> +      //        array temporary so we can model this properly.<br>
> +      for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)<br>
> +        performLifetimeExtension(ILE->getInit(I), ExtendingD);<br>
> +      return;<br>
> +    }<br>
> +<br>
> +    CXXRecordDecl *RD = Init->getType()->getAsCXXRecordDecl();<br>
> +    if (RD) {<br>
> +      assert(RD->isAggregate() && "aggregate init on non-aggregate");<br>
> +<br>
> +      // If we lifetime-extend a braced initializer which is initializing an<br>
> +      // aggregate, and that aggregate contains reference members which are<br>
> +      // bound to temporaries, those temporaries are also lifetime-extended.<br>
> +      if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&<br>
> +          ILE->getInitializedFieldInUnion()->getType()->isReferenceType())<br>
> +        performReferenceExtension(ILE->getInit(0), ExtendingD);<br>
> +      else {<br>
> +        unsigned Index = 0;<br>
> +        for (RecordDecl::field_iterator I = RD->field_begin(),<br>
> +                                        E = RD->field_end();<br>
> +             I != E; ++I) {<br>
> +          if (I->isUnnamedBitfield())<br>
> +            continue;<br>
> +          if (I->getType()->isReferenceType())<br>
> +            performReferenceExtension(ILE->getInit(Index), ExtendingD);<br>
> +          else if (isa<InitListExpr>(ILE->getInit(Index)))<br>
> +            // This may be either aggregate-initialization of a member or<br>
> +            // initialization of a std::initializer_list object. Either way,<br>
> +            // we should recursively lifetime-extend that initializer.<br>
> +            performLifetimeExtension(ILE->getInit(Index), ExtendingD);<br>
> +          ++Index;<br>
> +        }<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +}<br>
> +<br>
> ExprResult<br>
> InitializationSequence::Perform(Sema &S,<br>
>                                 const InitializedEntity &Entity,<br>
> @@ -5326,7 +5503,7 @@ InitializationSequence::Perform(Sema &S,<br>
><br>
>       break;<br>
><br>
> -    case SK_BindReferenceToTemporary:<br>
> +    case SK_BindReferenceToTemporary: {<br>
>       // Make sure the "temporary" is actually an rvalue.<br>
>       assert(CurInit.get()->isRValue() && "not a temporary");<br>
><br>
> @@ -5334,11 +5511,17 @@ InitializationSequence::Perform(Sema &S,<br>
>       if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))<br>
>         return ExprError();<br>
><br>
> +      // Maybe lifetime-extend the temporary's subobjects to match the<br>
> +      // entity's lifetime.<br>
> +      const ValueDecl *ExtendingDecl =<br>
> +          getDeclForTemporaryLifetimeExtension(Entity);<br>
> +      if (ExtendingDecl)<br>
> +        performLifetimeExtension(CurInit.get(), ExtendingDecl);<br>
> +<br>
>       // Materialize the temporary into memory.<br>
>       CurInit = new (S.Context) MaterializeTemporaryExpr(<br>
> -                                         Entity.getType().getNonReferenceType(),<br>
> -                                                         CurInit.get(),<br>
> -                                     Entity.getType()->isLValueReferenceType());<br>
> +          Entity.getType().getNonReferenceType(), CurInit.get(),<br>
> +          Entity.getType()->isLValueReferenceType(), ExtendingDecl);<br>
><br>
>       // If we're binding to an Objective-C object that has lifetime, we<br>
>       // need cleanups.<br>
> @@ -5347,6 +5530,7 @@ InitializationSequence::Perform(Sema &S,<br>
>         S.ExprNeedsCleanups = true;<br>
><br>
>       break;<br>
> +    }<br>
><br>
>     case SK_ExtraneousCopyToTemporary:<br>
>       CurInit = CopyObject(S, Step->Type, Entity, CurInit,<br>
><br>
> Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)<br>
> +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -1576,6 +1576,7 @@ void ASTStmtReader::VisitFunctionParmPac<br>
> void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {<br>
>   VisitExpr(E);<br>
>   E->Temporary = Reader.ReadSubExpr();<br>
> +  E->ExtendingDecl = ReadDeclAs<ValueDecl>(Record, Idx);<br>
> }<br>
><br>
> void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {<br>
><br>
> Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)<br>
> +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -1572,6 +1572,7 @@ void ASTStmtWriter::VisitFunctionParmPac<br>
> void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {<br>
>   VisitExpr(E);<br>
>   Writer.AddStmt(E->Temporary);<br>
> +  Writer.AddDeclRef(E->ExtendingDecl, Record);<br>
>   Code = serialization::EXPR_MATERIALIZE_TEMPORARY;<br>
> }<br>
><br>
><br>
> Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp (original)<br>
> +++ cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -224,12 +224,50 @@ namespace LiteralReference {<br>
>     constexpr Lit() : n(5) {}<br>
>     int n;<br>
>   };<br>
> -  // FIXME: This should have static initialization, but we do not implement<br>
> -  // that yet. For now, just check that we don't set the (pointer) value of<br>
> -  // the reference to 5!<br>
> -  //<br>
> -  // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null<br>
> +<br>
> +  // This creates a non-const temporary and binds a reference to it.<br>
> +  // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 5 }, align 4<br>
> +  // CHECK: @_ZN16LiteralReference3litE = constant {{.*}} @[[TEMP]], align 8<br>
>   const Lit &lit = Lit();<br>
> +<br>
> +  // This creates a const temporary as part of the reference initialization.<br>
> +  // CHECK: @[[TEMP:.*]] = private constant {{.*}} { i32 5 }, align 4<br>
> +  // CHECK: @_ZN16LiteralReference4lit2E = constant {{.*}} @[[TEMP]], align 8<br>
> +  const Lit &lit2 = {};<br>
> +<br>
> +  struct A { int &&r1; const int &&r2; };<br>
> +  struct B { A &&a1; const A &&a2; };<br>
> +  B b = { { 0, 1 }, { 2, 3 } };<br>
> +  // CHECK: @[[TEMP0:.*]] = private global i32 0, align 4<br>
> +  // CHECK: @[[TEMP1:.*]] = private constant i32 1, align 4<br>
> +  // CHECK: @[[TEMPA1:.*]] = private global {{.*}} { i32* @[[TEMP0]], i32* @[[TEMP1]] }, align 8<br>
> +  // CHECK: @[[TEMP2:.*]] = private global i32 2, align 4<br>
> +  // CHECK: @[[TEMP3:.*]] = private constant i32 3, align 4<br>
> +  // CHECK: @[[TEMPA2:.*]] = private constant {{.*}} { i32* @[[TEMP2]], i32* @[[TEMP3]] }, align 8<br>
> +  // CHECK: @_ZN16LiteralReference1bE = global {{.*}} { {{.*}}* @[[TEMPA1]], {{.*}}* @[[TEMPA2]] }, align 8<br>
> +<br>
> +  struct Subobj {<br>
> +    int a, b, c;<br>
> +  };<br>
> +  // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 1, i32 2, i32 3 }, align 4<br>
> +  // CHECK: @_ZN16LiteralReference2soE = constant {{.*}} (i8* getelementptr {{.*}} @[[TEMP]]{{.*}}, i64 4)<br>
> +  constexpr int &&so = Subobj{ 1, 2, 3 }.b;<br>
> +<br>
> +  struct Dummy { int padding; };<br>
> +  struct Derived : Dummy, Subobj {<br>
> +    constexpr Derived() : Dummy{200}, Subobj{4, 5, 6} {}<br>
> +  };<br>
> +  using ConstDerived = const Derived;<br>
> +  // CHECK: @[[TEMPCOMMA:.*]] = private constant {{.*}} { i32 200, i32 4, i32 5, i32 6 }<br>
> +  // CHECK: @_ZN16LiteralReference5commaE = constant {{.*}} getelementptr {{.*}} @[[TEMPCOMMA]]{{.*}}, i64 8)<br>
> +  constexpr const int &comma = (1, (2, ConstDerived{}).b);<br>
> +<br>
> +  // CHECK: @[[TEMPDERIVED:.*]] = private global {{.*}} { i32 200, i32 4, i32 5, i32 6 }<br>
> +  // CHECK: @_ZN16LiteralReference4baseE = constant {{.*}} getelementptr {{.*}} @[[TEMPDERIVED]]{{.*}}, i64 4)<br>
> +  constexpr Subobj &&base = Derived{};<br>
> +<br>
> +  // CHECK: @_ZN16LiteralReference7derivedE = constant {{.*}} @[[TEMPDERIVED]]<br>
> +  constexpr Derived &derived = static_cast<Derived&>(base);<br>
> }<br>
><br>
> namespace NonLiteralConstexpr {<br>
> @@ -330,6 +368,17 @@ namespace PR13273 {<br>
>   extern const S s {};<br>
> }<br>
><br>
> +namespace UnemittedTemporaryDecl {<br>
> +  constexpr int &&ref = 0;<br>
> +  extern constexpr int &ref2 = ref;<br>
> +  // CHECK: @_ZGRN22UnemittedTemporaryDecl3refE = private global i32 0<br>
> +<br>
> +  // FIXME: This declaration should not be emitted -- it isn't odr-used.<br>
> +  // CHECK: @_ZN22UnemittedTemporaryDecl3refE<br>
> +<br>
> +  // CHECK: @_ZN22UnemittedTemporaryDecl4ref2E = constant i32* @_ZGRN22UnemittedTemporaryDecl3refE<br>
> +}<br>
> +<br>
> // CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101<br>
> // CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102<br>
> // CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103<br>
><br>
> Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp (original)<br>
> +++ cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -17,4 +17,13 @@ B b;<br>
><br>
> // CHECK: @b = global {{.*}} i32 1, {{.*}} { i32 2 }, {{.*}} { i32 3 }, {{.*}} { i32 4 }<br>
> // CHECK-NOT: _ZN1BC<br>
> -// CHECK: __cxa_atexit<br>
> +<br>
> +namespace ModifyStaticTemporary {<br>
> +  struct A { int &&temporary; int x; };<br>
> +  constexpr int f(int &r) { r *= 9; return r - 12; }<br>
> +  A a = { 6, f(a.temporary) };<br>
> +  // CHECK: @_ZGRN21ModifyStaticTemporary1aE = private global i32 54<br>
> +  // CHECK: @_ZN21ModifyStaticTemporary1aE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1aE, i32 42<br>
> +}<br>
> +<br>
> +// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b<br>
><br>
> Modified: cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp (original)<br>
> +++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -284,4 +284,7 @@ namespace dtors {<br>
>   void f() {<br>
>     std::initializer_list<S>{ S(), S() };<br>
>   }<br>
> +  void g() {<br>
> +    auto x = std::initializer_list<S>{ S(), S() };<br>
> +  }<br>
> }<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -339,6 +339,30 @@ static_assert(!same(4, 4), "");<br>
> static_assert(same(n, n), "");<br>
> static_assert(sameTemporary(9), "");<br>
><br>
> +struct A { int &&r; };<br>
> +struct B { A &&a1; A &&a2; };<br>
> +<br>
> +constexpr B b1 { { 1 }, { 2 } }; // expected-note {{temporary created here}}<br>
> +static_assert(&b1.a1 != &b1.a2, "");<br>
> +static_assert(&b1.a1.r != &b1.a2.r, ""); // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}<br>
> +<br>
> +constexpr B &&b2 { { 3 }, { 4 } }; // expected-note {{temporary created here}}<br>
> +static_assert(&b1 != &b2, "");<br>
> +static_assert(&b1.a1 != &b2.a1, ""); // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}<br>
> +<br>
> +constexpr thread_local B b3 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}<br>
> +void foo() {<br>
> +  constexpr static B b1 { { 1 }, { 2 } }; // ok<br>
> +  constexpr thread_local B b2 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}<br>
> +  constexpr B b3 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}<br>
> +}<br>
> +<br>
> +constexpr B &&b4 = ((1, 2), 3, 4, B { {10}, {{20}} }); // expected-warning 4{{unused}}<br>
> +static_assert(&b4 != &b2, "");<br>
> +<br>
> +// Proposed DR: copy-elision doesn't trigger lifetime extension.<br>
> +constexpr B b5 = B{ {0}, {0} }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}<br>
> +<br>
> }<br>
><br>
> constexpr int strcmp_ce(const char *p, const char *q) {<br>
> @@ -572,7 +596,7 @@ struct E {<br>
>   constexpr E() : p(&p) {}<br>
>   void *p;<br>
> };<br>
> -constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{reference to temporary is not a constant expression}} expected-note {{temporary created here}}<br>
> +constexpr const E &e1 = E();<br>
> // This is a constant expression if we elide the copy constructor call, and<br>
> // is not a constant expression if we don't! But we do, so it is.<br>
> constexpr E e2 = E();<br>
> @@ -1282,8 +1306,23 @@ struct Wrap {<br>
> constexpr const Wrap &g(const Wrap &w) { return w; }<br>
> constexpr int k2 = g({0}).value; // ok<br>
><br>
> -constexpr const int &i = 0; // expected-error {{constant expression}} expected-note {{temporary}} expected-note 2{{here}}<br>
> -constexpr const int j = i; // expected-error {{constant expression}} expected-note {{initializer of 'i' is not a constant expression}}<br>
> +// The temporary here has static storage duration, so we can bind a constexpr<br>
> +// reference to it.<br>
> +constexpr const int &i = 1;<br>
> +constexpr const int j = i;<br>
> +static_assert(j == 1, "");<br>
> +<br>
> +// The temporary here is not const, so it can't be read outside the expression<br>
> +// in which it was created (per the C++14 rules, which we use to avoid a C++11<br>
> +// defect).<br>
> +constexpr int &&k = 1; // expected-note {{temporary created here}}<br>
> +constexpr const int l = k; // expected-error {{constant expression}} expected-note {{read of temporary}}<br>
> +<br>
> +void f() {<br>
> +  // The temporary here has automatic storage duration, so we can't bind a<br>
> +  // constexpr reference to it.<br>
> +  constexpr const int &i = 1; // expected-error {{constant expression}} expected-note 2{{temporary}}<br>
> +}<br>
><br>
> }<br>
><br>
><br>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=183283&r1=183282&r2=183283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=183283&r1=183282&r2=183283&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Tue Jun  4 19:46:14 2013<br>
> @@ -715,3 +715,13 @@ namespace deduced_return_type {<br>
>   static_assert(f() == 0, "");<br>
>   static_assert(g(true), "");<br>
> }<br>
> +<br>
> +namespace modify_temporary_during_construction {<br>
> +  struct A { int &&temporary; int x; int y; };<br>
> +  constexpr int f(int &r) { r *= 9; return r - 12; }<br>
> +  // FIXME: The 'uninitialized' warning here is bogus.<br>
> +  constexpr A a = { 6, f(a.temporary), a.temporary }; // expected-warning {{uninitialized}} expected-note {{temporary created here}}<br>
> +  static_assert(a.x == 42, "");<br>
> +  static_assert(a.y == 54, "");<br>
> +  constexpr int k = a.temporary++; // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}<br>
> +}<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
<br>
</div></div></blockquote></div><br>