r183283 - Model temporary lifetime-extension explicitly in the AST. Use this model to
Richard Smith
richard at metafoo.co.uk
Tue Jun 4 19:22:49 PDT 2013
On Tue, Jun 4, 2013 at 6:57 PM, Jordan Rose <jordan_rose at apple.com> wrote:
> 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.
:-) I've still not got to the miscompile I originally set out to fix here...
http://www.bcdb.com/cartoon_video/28426-Yak_Shaving_Day.html
> On Jun 4, 2013, at 17:46 , Richard Smith <richard-llvm at metafoo.co.uk>
> wrote:
>
> > Author: rsmith
> > Date: Tue Jun 4 19:46:14 2013
> > New Revision: 183283
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=183283&view=rev
> > Log:
> > Model temporary lifetime-extension explicitly in the AST. Use this model
> to
> > handle temporaries which have been lifetime-extended to static storage
> duration
> > within constant expressions. This correctly handles nested lifetime
> extension
> > (through reference members of aggregates in aggregate initializers) but
> > non-constant-expression emission hasn't yet been updated to do the same.
> >
> > Modified:
> > cfe/trunk/include/clang/AST/ASTContext.h
> > cfe/trunk/include/clang/AST/Decl.h
> > cfe/trunk/include/clang/AST/ExprCXX.h
> > cfe/trunk/include/clang/AST/Stmt.h
> > cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
> > cfe/trunk/include/clang/Basic/Specifiers.h
> > cfe/trunk/include/clang/Sema/Initialization.h
> > cfe/trunk/lib/AST/ASTContext.cpp
> > cfe/trunk/lib/AST/ASTDumper.cpp
> > cfe/trunk/lib/AST/ExprConstant.cpp
> > cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> > cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> > cfe/trunk/lib/CodeGen/CodeGenModule.h
> > cfe/trunk/lib/Sema/SemaExpr.cpp
> > cfe/trunk/lib/Sema/SemaInit.cpp
> > cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
> > cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
> > cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
> > cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp
> > cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
> > cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> > cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
> >
> > Modified: cfe/trunk/include/clang/AST/ASTContext.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> > +++ cfe/trunk/include/clang/AST/ASTContext.h Tue Jun 4 19:46:14 2013
> > @@ -55,6 +55,7 @@ namespace clang {
> > class ExternalASTSource;
> > class ASTMutationListener;
> > class IdentifierTable;
> > + class MaterializeTemporaryExpr;
> > class SelectorTable;
> > class TargetInfo;
> > class CXXABI;
> > @@ -163,6 +164,11 @@ class ASTContext : public RefCountedBase
> > llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
> > ClassScopeSpecializationPattern;
> >
> > + /// \brief Mapping from materialized temporaries with static storage
> duration
> > + /// that appear in constant initializers to their evaluated values.
> > + llvm::DenseMap<const MaterializeTemporaryExpr*, APValue>
> > + MaterializedTemporaryValues;
> > +
> > /// \brief Representation of a "canonical" template template parameter
> that
> > /// is used in canonical template names.
> > class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
> > @@ -2117,7 +2123,12 @@ public:
> > /// \brief Used by ParmVarDecl to retrieve on the side the
> > /// index of the parameter when it exceeds the size of the normal
> bitfield.
> > unsigned getParameterIndex(const ParmVarDecl *D) const;
> > -
> > +
> > + /// \brief Get the storage for the constant value of a materialized
> temporary
> > + /// of static storage duration.
> > + APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr
> *E,
> > + bool MayCreate);
> > +
> >
> //===--------------------------------------------------------------------===//
> > // Statistics
> >
> //===--------------------------------------------------------------------===//
> >
> > Modified: cfe/trunk/include/clang/AST/Decl.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/AST/Decl.h (original)
> > +++ cfe/trunk/include/clang/AST/Decl.h Tue Jun 4 19:46:14 2013
> > @@ -811,7 +811,7 @@ public:
> > bool hasLocalStorage() const {
> > if (getStorageClass() == SC_None)
> > // Second check is for C++11 [dcl.stc]p4.
> > - return !isFileVarDecl() && getTSCSpec() != TSCS_thread_local;
> > + return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
> >
> > // Return true for: Auto, Register.
> > // Return false for: Extern, Static, PrivateExtern,
> OpenCLWorkGroupLocal.
> > @@ -840,6 +840,12 @@ public:
> > /// as static variables declared within a function.
> > bool hasGlobalStorage() const { return !hasLocalStorage(); }
> >
> > + /// \brief Get the storage duration of this variable, per C++
> [basid.stc].
> > + StorageDuration getStorageDuration() const {
> > + return hasLocalStorage() ? SD_Automatic :
> > + getTSCSpec() ? SD_Thread : SD_Static;
> > + }
> > +
> > /// Compute the language linkage.
> > LanguageLinkage getLanguageLinkage() const;
> >
> >
> > Modified: cfe/trunk/include/clang/AST/ExprCXX.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/AST/ExprCXX.h (original)
> > +++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Jun 4 19:46:14 2013
> > @@ -3824,30 +3824,60 @@ public:
> > /// 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.
> > +///
> > +/// Reference binding and copy-elision can both extend the lifetime of a
> > +/// temporary. When either happens, the expression will also track the
> > +/// declaration which is responsible for the lifetime extension.
> > class MaterializeTemporaryExpr : public Expr {
> > +public:
> > /// \brief The temporary-generating expression whose value will be
> > /// materialized.
> > Stmt *Temporary;
> >
> > + /// \brief The declaration which lifetime-extended this reference, if
> any.
> > + /// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.
> > + const ValueDecl *ExtendingDecl;
> > +
> > friend class ASTStmtReader;
> > friend class ASTStmtWriter;
> >
> > public:
> > MaterializeTemporaryExpr(QualType T, Expr *Temporary,
> > - bool BoundToLvalueReference)
> > + bool BoundToLvalueReference,
> > + const ValueDecl *ExtendedBy)
> > : Expr(MaterializeTemporaryExprClass, T,
> > BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,
> > Temporary->isTypeDependent(), Temporary->isValueDependent(),
> > Temporary->isInstantiationDependent(),
> > Temporary->containsUnexpandedParameterPack()),
> > - Temporary(Temporary) { }
> > + Temporary(Temporary), ExtendingDecl(ExtendedBy) {
> > + }
> >
> > 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); }
> > + Expr *GetTemporaryExpr() const { return static_cast<Expr
> *>(Temporary); }
> > +
> > + /// \brief Retrieve the storage duration for the materialized
> temporary.
> > + StorageDuration getStorageDuration() const {
> > + if (!ExtendingDecl)
> > + return SD_FullExpression;
> > + // FIXME: This is not necessarily correct for a temporary
> materialized
> > + // within a default initializer.
> > + if (isa<FieldDecl>(ExtendingDecl))
> > + return SD_Automatic;
> > + return cast<VarDecl>(ExtendingDecl)->getStorageDuration();
> > + }
> > +
> > + /// \brief Get the declaration which triggered the lifetime-extension
> of this
> > + /// temporary, if any.
> > + const ValueDecl *getExtendingDecl() const { return ExtendingDecl; }
> > +
> > + void setExtendingDecl(const ValueDecl *ExtendedBy) {
> > + ExtendingDecl = ExtendedBy;
> > + }
> >
> > /// \brief Determine whether this materialized temporary is bound to an
> > /// lvalue reference; otherwise, it's bound to an rvalue reference.
> >
> > Modified: cfe/trunk/include/clang/AST/Stmt.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/AST/Stmt.h (original)
> > +++ cfe/trunk/include/clang/AST/Stmt.h Tue Jun 4 19:46:14 2013
> > @@ -289,7 +289,7 @@ protected:
> > /// \brief The number of arguments to this type trait.
> > unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
> > };
> > -
> > +
> > union {
> > // FIXME: this is wasteful on 64-bit platforms.
> > void *Aligner;
> >
> > Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
> > +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Tue Jun 4
> 19:46:14 2013
> > @@ -117,6 +117,10 @@ def note_constexpr_access_inactive_union
> > "%select{read of|assignment to|increment of|decrement of}0 "
> > "member %1 of union with %select{active member %3|no active member}2 "
> > "is not allowed in a constant expression">;
> > +def note_constexpr_access_static_temporary : Note<
> > + "%select{read of|assignment to|increment of|decrement of}0 temporary "
> > + "is not allowed in a constant expression outside the expression that "
> > + "created the temporary">;
> > def note_constexpr_modify_global : Note<
> > "a constant expression cannot modify an object that is visible outside
> "
> > "that expression">;
> >
> > Modified: cfe/trunk/include/clang/Basic/Specifiers.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/Basic/Specifiers.h (original)
> > +++ cfe/trunk/include/clang/Basic/Specifiers.h Tue Jun 4 19:46:14 2013
> > @@ -212,6 +212,14 @@ namespace clang {
> > CC_IntelOclBicc // __attribute__((intel_ocl_bicc))
> > };
> >
> > + /// \brief The storage duration for an object (per C++ [basic.stc]).
> > + enum StorageDuration {
> > + SD_FullExpression, ///< Full-expression storage duration (for
> temporaries).
> > + SD_Automatic, ///< Automatic storage duration (most local
> variables).
> > + SD_Thread, ///< Thread storage duration.
> > + SD_Static, ///< Static storage duration.
> > + SD_Dynamic ///< Dynamic storage duration.
> > + };
> > } // end namespace clang
> >
> > #endif // LLVM_CLANG_BASIC_SPECIFIERS_H
> >
> > Modified: cfe/trunk/include/clang/Sema/Initialization.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/Sema/Initialization.h (original)
> > +++ cfe/trunk/include/clang/Sema/Initialization.h Tue Jun 4 19:46:14
> 2013
> > @@ -384,6 +384,13 @@ public:
> > assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
> > return SourceLocation::getFromRawEncoding(Capture.Location);
> > }
> > +
> > + /// Dump a representation of the initialized entity to standard error,
> > + /// for debugging purposes.
> > + void dump() const;
> > +
> > +private:
> > + unsigned dumpImpl(raw_ostream &OS) const;
> > };
> >
> > /// \brief Describes the kind of initialization being performed, along
> with
> >
> > Modified: cfe/trunk/lib/AST/ASTContext.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> > +++ cfe/trunk/lib/AST/ASTContext.cpp Tue Jun 4 19:46:14 2013
> > @@ -8029,6 +8029,19 @@ unsigned ASTContext::getParameterIndex(c
> > return I->second;
> > }
> >
> > +APValue *
> > +ASTContext::getMaterializedTemporaryValue(const
> MaterializeTemporaryExpr *E,
> > + bool MayCreate) {
> > + assert(E && E->getStorageDuration() == SD_Static &&
> > + "don't need to cache the computed value for this temporary");
> > + if (MayCreate)
> > + return &MaterializedTemporaryValues[E];
> > +
> > + llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I
> =
> > + MaterializedTemporaryValues.find(E);
> > + return I == MaterializedTemporaryValues.end() ? 0 : &I->second;
> > +}
> > +
> > bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const
> {
> > const llvm::Triple &T = getTargetInfo().getTriple();
> > if (!T.isOSDarwin())
> >
> > Modified: cfe/trunk/lib/AST/ASTDumper.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/AST/ASTDumper.cpp (original)
> > +++ cfe/trunk/lib/AST/ASTDumper.cpp Tue Jun 4 19:46:14 2013
> > @@ -274,6 +274,7 @@ namespace {
> > void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
> > void VisitCXXConstructExpr(const CXXConstructExpr *Node);
> > void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
> > + void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr
> *Node);
> > void VisitExprWithCleanups(const ExprWithCleanups *Node);
> > void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
> > void dumpCXXTemporary(const CXXTemporary *Temporary);
> > @@ -1682,6 +1683,15 @@ void ASTDumper::VisitCXXBindTemporaryExp
> > dumpCXXTemporary(Node->getTemporary());
> > }
> >
> > +void
> > +ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr
> *Node) {
> > + VisitExpr(Node);
> > + if (const ValueDecl *VD = Node->getExtendingDecl()) {
> > + OS << " extended by ";
> > + dumpBareDeclRef(VD);
> > + }
> > +}
> > +
> > void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
> > VisitExpr(Node);
> > for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
> >
> > Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> > +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Jun 4 19:46:14 2013
> > @@ -1001,6 +1001,10 @@ static bool IsGlobalLValue(APValue::LVal
> > const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
> > return CLE->isFileScope() && CLE->isLValue();
> > }
> > + case Expr::MaterializeTemporaryExprClass:
> > + // A materialized temporary might have been lifetime-extended to
> static
> > + // storage duration.
> > + return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() ==
> SD_Static;
> > // A string literal has static storage duration.
> > case Expr::StringLiteralClass:
> > case Expr::PredefinedExprClass:
> > @@ -1182,7 +1186,10 @@ const ValueDecl *GetLValueBaseDecl(const
> > }
> >
> > static bool IsLiteralLValue(const LValue &Value) {
> > - return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
> > + if (Value.CallIndex)
> > + return false;
> > + const Expr *E = Value.Base.dyn_cast<const Expr*>();
> > + return E && !isa<MaterializeTemporaryExpr>(E);
> > }
> >
> > static bool IsWeakLValue(const LValue &Value) {
> > @@ -2279,11 +2286,44 @@ CompleteObject findCompleteObject(EvalIn
> > const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
> >
> > if (!Frame) {
> > - Info.Diag(E);
> > - return CompleteObject();
> > - }
> > + if (const MaterializeTemporaryExpr *MTE =
> > + dyn_cast<MaterializeTemporaryExpr>(Base)) {
> > + assert(MTE->getStorageDuration() == SD_Static &&
> > + "should have a frame for a non-global materialized
> temporary");
> > +
> > + // Per C++1y [expr.const]p2:
> > + // an lvalue-to-rvalue conversion [is not allowed unless it
> applies to]
> > + // - a [...] glvalue of integral or enumeration type that
> refers to
> > + // a non-volatile const object [...]
> > + // [...]
> > + // - a [...] glvalue of literal type that refers to a
> non-volatile
> > + // object whose lifetime began within the evaluation of e.
> > + //
> > + // C++11 misses the 'began within the evaluation of e' check and
> > + // instead allows all temporaries, including things like:
> > + // int &&r = 1;
> > + // int x = ++r;
> > + // constexpr int k = r;
> > + // Therefore we use the C++1y rules in C++11 too.
> > + const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const
> ValueDecl*>();
> > + const ValueDecl *ED = MTE->getExtendingDecl();
> > + if (!(BaseType.isConstQualified() &&
> > + BaseType->isIntegralOrEnumerationType()) &&
> > + !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
> > + Info.Diag(E, diag::note_constexpr_access_static_temporary, 1)
> << AK;
> > + Info.Note(MTE->getExprLoc(),
> diag::note_constexpr_temporary_here);
> > + return CompleteObject();
> > + }
> >
> > - BaseVal = &Frame->Temporaries[Base];
> > + BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
> > + assert(BaseVal && "got reference to unevaluated temporary");
> > + } else {
> > + Info.Diag(E);
> > + return CompleteObject();
> > + }
> > + } else {
> > + BaseVal = &Frame->Temporaries[Base];
> > + }
> >
> > // Volatile temporary objects cannot be accessed in constant
> expressions.
> > if (BaseType.isVolatileQualified()) {
> > @@ -3940,6 +3980,8 @@ public:
> > // * Any Expr, with a CallIndex indicating the function in which the
> temporary
> > // was evaluated, for cases where the MaterializeTemporaryExpr is
> missing
> > // from the AST (FIXME).
> > +// * A MaterializeTemporaryExpr that has static storage duration, with
> no
> > +// CallIndex, for a lifetime-extended temporary.
> > // plus an offset in bytes.
> >
> //===----------------------------------------------------------------------===//
> > namespace {
> > @@ -4045,9 +4087,19 @@ bool LValueExprEvaluator::VisitMateriali
> > if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))
> > return false;
> >
> > + // A materialized temporary with static storage duration can appear
> within the
> > + // result of a constant expression evaluation, so we need to preserve
> its
> > + // value for use outside this evaluation.
> > + APValue *Value;
> > + if (E->getStorageDuration() == SD_Static) {
> > + Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
> > + Result.set(E);
> > + } else {
> > + Value = &Info.CurrentCall->Temporaries[E];
> > + Result.set(E, Info.CurrentCall->Index);
> > + }
> > +
> > // Materialize the temporary itself.
> > - APValue *Value = &Info.CurrentCall->Temporaries[E];
> > - Result.set(E, Info.CurrentCall->Index);
> > if (!EvaluateInPlace(*Value, Info, Result, Inner))
> > return false;
> >
> > @@ -7608,10 +7660,10 @@ void Expr::EvaluateForOverflow(const AST
> > }
> > }
> >
> > - bool Expr::EvalResult::isGlobalLValue() const {
> > - assert(Val.isLValue());
> > - return IsGlobalLValue(Val.getLValueBase());
> > - }
> > +bool Expr::EvalResult::isGlobalLValue() const {
> > + assert(Val.isLValue());
> > + return IsGlobalLValue(Val.getLValueBase());
> > +}
> >
> >
> > /// isIntegerConstantExpr - this recursive routine will test if an
> expression is
> >
> > Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
> > +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Tue Jun 4 19:46:14 2013
> > @@ -1003,6 +1003,15 @@ public:
> > case Expr::CXXUuidofExprClass: {
> > return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E));
> > }
> > + case Expr::MaterializeTemporaryExprClass: {
> > + MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
> > + assert(MTE->getStorageDuration() == SD_Static);
> > + SmallVector<const Expr *, 2> CommaLHSs;
> > + SmallVector<SubobjectAdjustment, 2> Adjustments;
> > + const Expr *Inner = MTE->GetTemporaryExpr()
> > + ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
> > + return CGM.GetAddrOfGlobalTemporary(MTE, Inner);
> > + }
> > }
> >
> > return 0;
> >
> > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> > +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Jun 4 19:46:14 2013
> > @@ -2735,6 +2735,63 @@ llvm::Constant *CodeGenModule::GetAddrOf
> > return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment);
> > }
> >
> > +llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
> > + const MaterializeTemporaryExpr *E, const Expr *Inner) {
> > + assert((E->getStorageDuration() == SD_Static ||
> > + E->getStorageDuration() == SD_Thread) && "not a global
> temporary");
> > + const VarDecl *VD = cast<VarDecl>(E->getExtendingDecl());
> > +
> > + // If we're not materializing a subobject of the temporary, keep the
> > + // cv-qualifiers from the type of the MaterializeTemporaryExpr.
> > + if (Inner == E->GetTemporaryExpr())
> > + Inner = E;
> > +
> > + llvm::Constant *&Slot = MaterializedGlobalTemporaryMap[E];
> > + if (Slot)
> > + return Slot;
> > +
> > + // FIXME: If an externally-visible declaration extends multiple
> temporaries,
> > + // we need to give each temporary the same name in every translation
> unit (and
> > + // we also need to make the temporaries externally-visible).
> > + SmallString<256> Name;
> > + llvm::raw_svector_ostream Out(Name);
> > + getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
> > + Out.flush();
> > +
> > + llvm::Constant *InitialValue = 0;
> > + APValue *Value = 0;
> > + if (E->getStorageDuration() == SD_Static) {
> > + // We might have a constant initializer for this temporary.
> > + Value = getContext().getMaterializedTemporaryValue(E, false);
> > + if (Value && Value->isUninit())
> > + Value = 0;
> > + }
> > +
> > + bool Constant;
> > + if (Value) {
> > + // The temporary has a constant initializer, use it.
> > + InitialValue = EmitConstantValue(*Value, Inner->getType(), 0);
> > + Constant = isTypeConstant(Inner->getType(), /*ExcludeCtor*/Value);
> > + } else {
> > + // No constant initializer, the initialization will be provided
> when we
> > + // initialize the declaration which performed lifetime extension.
> > + InitialValue = EmitNullConstant(Inner->getType());
> > + Constant = false;
> > + }
> > +
> > + // Create a global variable for this lifetime-extended temporary.
> > + llvm::GlobalVariable *GV =
> > + new llvm::GlobalVariable(getModule(), InitialValue->getType(),
> Constant,
> > + llvm::GlobalValue::PrivateLinkage,
> InitialValue,
> > + Name.c_str());
> > + GV->setAlignment(
> > + getContext().getTypeAlignInChars(Inner->getType()).getQuantity());
> > + if (VD->getTLSKind())
> > + setTLSMode(GV, *VD);
> > + Slot = GV;
> > + return GV;
> > +}
> > +
> > /// EmitObjCPropertyImplementations - Emit information for synthesized
> > /// properties for an implementation.
> > void CodeGenModule::EmitObjCPropertyImplementations(const
> >
> > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> > +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Jun 4 19:46:14 2013
> > @@ -307,7 +307,8 @@ class CodeGenModule : public CodeGenType
> > llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
> > llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
> > llvm::DenseMap<const Decl*, llvm::GlobalVariable*>
> StaticLocalDeclGuardMap;
> > -
> > + llvm::DenseMap<const Expr*, llvm::Constant *>
> MaterializedGlobalTemporaryMap;
> > +
> > llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
> > llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
> >
> > @@ -731,7 +732,12 @@ public:
> > /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant
> global
> > /// variable for the given file-scope compound literal expression.
> > llvm::Constant *GetAddrOfConstantCompoundLiteral(const
> CompoundLiteralExpr*E);
> > -
> > +
> > + /// \brief Returns a pointer to a global variable representing a
> temporary
> > + /// with static or thread storage duration.
> > + llvm::Constant *GetAddrOfGlobalTemporary(const
> MaterializeTemporaryExpr *E,
> > + const Expr *Inner);
> > +
> > /// \brief Retrieve the record type that describes the state of an
> > /// Objective-C fast enumeration loop (for..in).
> > QualType getObjCFastEnumerationStateType();
> >
> > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 4 19:46:14 2013
> > @@ -8353,7 +8353,7 @@ static QualType CheckAddressOfOperand(Se
> > return QualType();
> > // Materialize the temporary as an lvalue so that we can take its
> address.
> > OrigOp = op = new (S.Context)
> > - MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true);
> > + MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true, 0);
> > } else if (isa<ObjCSelectorExpr>(op)) {
> > return S.Context.getPointerType(op->getType());
> > } else if (lval == Expr::LV_MemberFunction) {
> >
> > Modified: cfe/trunk/lib/Sema/SemaInit.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jun 4 19:46:14 2013
> > @@ -2502,6 +2502,46 @@ bool InitializedEntity::allowsNRVO() con
> > return false;
> > }
> >
> > +unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
> > + unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;
> > + for (unsigned I = 0; I != Depth; ++I)
> > + OS << "`-";
> > +
> > + switch (getKind()) {
> > + case EK_Variable: OS << "Variable"; break;
> > + case EK_Parameter: OS << "Parameter"; break;
> > + case EK_Result: OS << "Result"; break;
> > + case EK_Exception: OS << "Exception"; break;
> > + case EK_Member: OS << "Member"; break;
> > + case EK_New: OS << "New"; break;
> > + case EK_Temporary: OS << "Temporary"; break;
> > + case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
> > + case EK_Base: OS << "Base"; break;
> > + case EK_Delegating: OS << "Delegating"; break;
> > + case EK_ArrayElement: OS << "ArrayElement " << Index; break;
> > + case EK_VectorElement: OS << "VectorElement " << Index; break;
> > + case EK_ComplexElement: OS << "ComplexElement " << Index; break;
> > + case EK_BlockElement: OS << "Block"; break;
> > + case EK_LambdaCapture:
> > + OS << "LambdaCapture ";
> > + getCapturedVar()->printName(OS);
> > + break;
> > + }
> > +
> > + if (Decl *D = getDecl()) {
> > + OS << " ";
> > + cast<NamedDecl>(D)->printQualifiedName(OS);
> > + }
> > +
> > + OS << " '" << getType().getAsString() << "'\n";
> > +
> > + return Depth + 1;
> > +}
> > +
> > +void InitializedEntity::dump() const {
> > + dumpImpl(llvm::errs());
> > +}
> > +
> >
> //===----------------------------------------------------------------------===//
> > // Initialization sequence
> >
> //===----------------------------------------------------------------------===//
> > @@ -5089,6 +5129,143 @@ InitializedEntityOutlivesFullExpression(
> > llvm_unreachable("unknown entity kind");
> > }
> >
> > +/// Determine the declaration which an initialized entity ultimately
> refers to,
> > +/// for the purpose of lifetime-extending a temporary bound to a
> reference in
> > +/// the initialization of \p Entity.
> > +static const ValueDecl *
> > +getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
> > + const ValueDecl *FallbackDecl = 0)
> {
> > + // C++11 [class.temporary]p5:
> > + switch (Entity.getKind()) {
> > + case InitializedEntity::EK_Variable:
> > + // The temporary [...] persists for the lifetime of the reference
> > + return Entity.getDecl();
> > +
> > + case InitializedEntity::EK_Member:
> > + // For subobjects, we look at the complete object.
> > + if (Entity.getParent())
> > + return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
> > + Entity.getDecl());
> > +
> > + // except:
> > + // -- A temporary bound to a reference member in a constructor's
> > + // ctor-initializer persists until the constructor exits.
> > + return Entity.getDecl();
> > +
> > + case InitializedEntity::EK_Parameter:
> > + // -- A temporary bound to a reference parameter in a function
> call
> > + // persists until the completion of the full-expression
> containing
> > + // the call.
> > + case InitializedEntity::EK_Result:
> > + // -- The lifetime of a temporary bound to the returned value in a
> > + // function return statement is not extended; the temporary is
> > + // destroyed at the end of the full-expression in the return
> statement.
> > + case InitializedEntity::EK_New:
> > + // -- A temporary bound to a reference in a new-initializer
> persists
> > + // until the completion of the full-expression containing the
> > + // new-initializer.
> > + return 0;
> > +
> > + case InitializedEntity::EK_Temporary:
> > + case InitializedEntity::EK_CompoundLiteralInit:
> > + // We don't yet know the storage duration of the surrounding
> temporary.
> > + // Assume it's got full-expression duration for now, it will patch
> up our
> > + // storage duration if that's not correct.
> > + return 0;
> > +
> > + case InitializedEntity::EK_ArrayElement:
> > + // For subobjects, we look at the complete object.
> > + return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
> > + FallbackDecl);
> > +
> > + case InitializedEntity::EK_Base:
> > + case InitializedEntity::EK_Delegating:
> > + // We can reach this case for aggregate initialization in a
> constructor:
> > + // struct A { int &&r; };
> > + // struct B : A { B() : A{0} {} };
> > + // In this case, use the innermost field decl as the context.
> > + return FallbackDecl;
> > +
> > + case InitializedEntity::EK_BlockElement:
> > + case InitializedEntity::EK_LambdaCapture:
> > + case InitializedEntity::EK_Exception:
> > + case InitializedEntity::EK_VectorElement:
> > + case InitializedEntity::EK_ComplexElement:
> > + llvm_unreachable("should not materialize a temporary to initialize
> this");
> > + }
> > +}
> > +
> > +static void performLifetimeExtension(Expr *Init, const ValueDecl
> *ExtendingD);
> > +
> > +/// Update a glvalue expression that is used as the initializer of a
> reference
> > +/// to note that its lifetime is extended.
> > +static void performReferenceExtension(Expr *Init, const ValueDecl
> *ExtendingD) {
> > + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
> > + if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
> > + // This is just redundant braces around an initializer. Step over
> it.
> > + Init = ILE->getInit(0);
> > + }
> > + }
> > +
> > + if (MaterializeTemporaryExpr *ME =
> dyn_cast<MaterializeTemporaryExpr>(Init)) {
> > + // Update the storage duration of the materialized temporary.
> > + // FIXME: Rebuild the expression instead of mutating it.
> > + ME->setExtendingDecl(ExtendingD);
> > + performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD);
> > + }
> > +}
> > +
> > +/// Update a prvalue expression that is going to be materialized as a
> > +/// lifetime-extended temporary.
> > +static void performLifetimeExtension(Expr *Init, const ValueDecl
> *ExtendingD) {
> > + // Dig out the expression which constructs the extended temporary.
> > + SmallVector<const Expr *, 2> CommaLHSs;
> > + SmallVector<SubobjectAdjustment, 2> Adjustments;
> > + Init = const_cast<Expr *>(
> > + Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
> > +
> > + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
> > + if (ILE->initializesStdInitializerList()) {
> > + // FIXME: If this is an InitListExpr which creates a
> std::initializer_list
> > + // object, we also need to lifetime-extend the underlying
> array
> > + // itself. Fix the representation to explicitly
> materialize an
> > + // array temporary so we can model this properly.
> > + for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
> > + performLifetimeExtension(ILE->getInit(I), ExtendingD);
> > + return;
> > + }
> > +
> > + CXXRecordDecl *RD = Init->getType()->getAsCXXRecordDecl();
> > + if (RD) {
> > + assert(RD->isAggregate() && "aggregate init on non-aggregate");
> > +
> > + // If we lifetime-extend a braced initializer which is
> initializing an
> > + // aggregate, and that aggregate contains reference members which
> are
> > + // bound to temporaries, those temporaries are also
> lifetime-extended.
> > + if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
> > +
> ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
> > + performReferenceExtension(ILE->getInit(0), ExtendingD);
> > + else {
> > + unsigned Index = 0;
> > + for (RecordDecl::field_iterator I = RD->field_begin(),
> > + E = RD->field_end();
> > + I != E; ++I) {
> > + if (I->isUnnamedBitfield())
> > + continue;
> > + if (I->getType()->isReferenceType())
> > + performReferenceExtension(ILE->getInit(Index), ExtendingD);
> > + else if (isa<InitListExpr>(ILE->getInit(Index)))
> > + // This may be either aggregate-initialization of a member
> or
> > + // initialization of a std::initializer_list object. Either
> way,
> > + // we should recursively lifetime-extend that initializer.
> > + performLifetimeExtension(ILE->getInit(Index), ExtendingD);
> > + ++Index;
> > + }
> > + }
> > + }
> > + }
> > +}
> > +
> > ExprResult
> > InitializationSequence::Perform(Sema &S,
> > const InitializedEntity &Entity,
> > @@ -5326,7 +5503,7 @@ InitializationSequence::Perform(Sema &S,
> >
> > break;
> >
> > - case SK_BindReferenceToTemporary:
> > + case SK_BindReferenceToTemporary: {
> > // Make sure the "temporary" is actually an rvalue.
> > assert(CurInit.get()->isRValue() && "not a temporary");
> >
> > @@ -5334,11 +5511,17 @@ InitializationSequence::Perform(Sema &S,
> > if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
> > return ExprError();
> >
> > + // Maybe lifetime-extend the temporary's subobjects to match the
> > + // entity's lifetime.
> > + const ValueDecl *ExtendingDecl =
> > + getDeclForTemporaryLifetimeExtension(Entity);
> > + if (ExtendingDecl)
> > + performLifetimeExtension(CurInit.get(), ExtendingDecl);
> > +
> > // Materialize the temporary into memory.
> > CurInit = new (S.Context) MaterializeTemporaryExpr(
> > -
> Entity.getType().getNonReferenceType(),
> > - CurInit.get(),
> > -
> Entity.getType()->isLValueReferenceType());
> > + Entity.getType().getNonReferenceType(), CurInit.get(),
> > + Entity.getType()->isLValueReferenceType(), ExtendingDecl);
> >
> > // If we're binding to an Objective-C object that has lifetime, we
> > // need cleanups.
> > @@ -5347,6 +5530,7 @@ InitializationSequence::Perform(Sema &S,
> > S.ExprNeedsCleanups = true;
> >
> > break;
> > + }
> >
> > case SK_ExtraneousCopyToTemporary:
> > CurInit = CopyObject(S, Step->Type, Entity, CurInit,
> >
> > Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
> > +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Jun 4 19:46:14
> 2013
> > @@ -1576,6 +1576,7 @@ void ASTStmtReader::VisitFunctionParmPac
> > void
> ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
> > VisitExpr(E);
> > E->Temporary = Reader.ReadSubExpr();
> > + E->ExtendingDecl = ReadDeclAs<ValueDecl>(Record, Idx);
> > }
> >
> > void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
> >
> > Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
> > +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Jun 4 19:46:14
> 2013
> > @@ -1572,6 +1572,7 @@ void ASTStmtWriter::VisitFunctionParmPac
> > void
> ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
> > VisitExpr(E);
> > Writer.AddStmt(E->Temporary);
> > + Writer.AddDeclRef(E->ExtendingDecl, Record);
> > Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
> > }
> >
> >
> > Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp (original)
> > +++ cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp Tue Jun 4 19:46:14
> 2013
> > @@ -224,12 +224,50 @@ namespace LiteralReference {
> > constexpr Lit() : n(5) {}
> > int n;
> > };
> > - // FIXME: This should have static initialization, but we do not
> implement
> > - // that yet. For now, just check that we don't set the (pointer)
> value of
> > - // the reference to 5!
> > - //
> > - // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null
> > +
> > + // This creates a non-const temporary and binds a reference to it.
> > + // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 5 }, align 4
> > + // CHECK: @_ZN16LiteralReference3litE = constant {{.*}} @[[TEMP]],
> align 8
> > const Lit &lit = Lit();
> > +
> > + // This creates a const temporary as part of the reference
> initialization.
> > + // CHECK: @[[TEMP:.*]] = private constant {{.*}} { i32 5 }, align 4
> > + // CHECK: @_ZN16LiteralReference4lit2E = constant {{.*}} @[[TEMP]],
> align 8
> > + const Lit &lit2 = {};
> > +
> > + struct A { int &&r1; const int &&r2; };
> > + struct B { A &&a1; const A &&a2; };
> > + B b = { { 0, 1 }, { 2, 3 } };
> > + // CHECK: @[[TEMP0:.*]] = private global i32 0, align 4
> > + // CHECK: @[[TEMP1:.*]] = private constant i32 1, align 4
> > + // CHECK: @[[TEMPA1:.*]] = private global {{.*}} { i32* @[[TEMP0]],
> i32* @[[TEMP1]] }, align 8
> > + // CHECK: @[[TEMP2:.*]] = private global i32 2, align 4
> > + // CHECK: @[[TEMP3:.*]] = private constant i32 3, align 4
> > + // CHECK: @[[TEMPA2:.*]] = private constant {{.*}} { i32* @[[TEMP2]],
> i32* @[[TEMP3]] }, align 8
> > + // CHECK: @_ZN16LiteralReference1bE = global {{.*}} { {{.*}}*
> @[[TEMPA1]], {{.*}}* @[[TEMPA2]] }, align 8
> > +
> > + struct Subobj {
> > + int a, b, c;
> > + };
> > + // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 1, i32 2, i32 3
> }, align 4
> > + // CHECK: @_ZN16LiteralReference2soE = constant {{.*}} (i8*
> getelementptr {{.*}} @[[TEMP]]{{.*}}, i64 4)
> > + constexpr int &&so = Subobj{ 1, 2, 3 }.b;
> > +
> > + struct Dummy { int padding; };
> > + struct Derived : Dummy, Subobj {
> > + constexpr Derived() : Dummy{200}, Subobj{4, 5, 6} {}
> > + };
> > + using ConstDerived = const Derived;
> > + // CHECK: @[[TEMPCOMMA:.*]] = private constant {{.*}} { i32 200, i32
> 4, i32 5, i32 6 }
> > + // CHECK: @_ZN16LiteralReference5commaE = constant {{.*}}
> getelementptr {{.*}} @[[TEMPCOMMA]]{{.*}}, i64 8)
> > + constexpr const int &comma = (1, (2, ConstDerived{}).b);
> > +
> > + // CHECK: @[[TEMPDERIVED:.*]] = private global {{.*}} { i32 200, i32
> 4, i32 5, i32 6 }
> > + // CHECK: @_ZN16LiteralReference4baseE = constant {{.*}}
> getelementptr {{.*}} @[[TEMPDERIVED]]{{.*}}, i64 4)
> > + constexpr Subobj &&base = Derived{};
> > +
> > + // CHECK: @_ZN16LiteralReference7derivedE = constant {{.*}}
> @[[TEMPDERIVED]]
> > + constexpr Derived &derived = static_cast<Derived&>(base);
> > }
> >
> > namespace NonLiteralConstexpr {
> > @@ -330,6 +368,17 @@ namespace PR13273 {
> > extern const S s {};
> > }
> >
> > +namespace UnemittedTemporaryDecl {
> > + constexpr int &&ref = 0;
> > + extern constexpr int &ref2 = ref;
> > + // CHECK: @_ZGRN22UnemittedTemporaryDecl3refE = private global i32 0
> > +
> > + // FIXME: This declaration should not be emitted -- it isn't odr-used.
> > + // CHECK: @_ZN22UnemittedTemporaryDecl3refE
> > +
> > + // CHECK: @_ZN22UnemittedTemporaryDecl4ref2E = constant i32*
> @_ZGRN22UnemittedTemporaryDecl3refE
> > +}
> > +
> > // CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101
> > // CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32
> 102
> > // CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr
> constant {{.*}} i32 103
> >
> > Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp (original)
> > +++ cfe/trunk/test/CodeGenCXX/const-init-cxx1y.cpp Tue Jun 4 19:46:14
> 2013
> > @@ -17,4 +17,13 @@ B b;
> >
> > // CHECK: @b = global {{.*}} i32 1, {{.*}} { i32 2 }, {{.*}} { i32 3 },
> {{.*}} { i32 4 }
> > // CHECK-NOT: _ZN1BC
> > -// CHECK: __cxa_atexit
> > +
> > +namespace ModifyStaticTemporary {
> > + struct A { int &&temporary; int x; };
> > + constexpr int f(int &r) { r *= 9; return r - 12; }
> > + A a = { 6, f(a.temporary) };
> > + // CHECK: @_ZGRN21ModifyStaticTemporary1aE = private global i32 54
> > + // CHECK: @_ZN21ModifyStaticTemporary1aE = global {{.*}} i32*
> @_ZGRN21ModifyStaticTemporary1aE, i32 42
> > +}
> > +
> > +// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b
> >
> > Modified:
> cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
> (original)
> > +++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
> Tue Jun 4 19:46:14 2013
> > @@ -284,4 +284,7 @@ namespace dtors {
> > void f() {
> > std::initializer_list<S>{ S(), S() };
> > }
> > + void g() {
> > + auto x = std::initializer_list<S>{ S(), S() };
> > + }
> > }
> >
> > Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
> > +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Jun 4
> 19:46:14 2013
> > @@ -339,6 +339,30 @@ static_assert(!same(4, 4), "");
> > static_assert(same(n, n), "");
> > static_assert(sameTemporary(9), "");
> >
> > +struct A { int &&r; };
> > +struct B { A &&a1; A &&a2; };
> > +
> > +constexpr B b1 { { 1 }, { 2 } }; // expected-note {{temporary created
> here}}
> > +static_assert(&b1.a1 != &b1.a2, "");
> > +static_assert(&b1.a1.r != &b1.a2.r, ""); // expected-error {{constant
> expression}} expected-note {{outside the expression that created the
> temporary}}
> > +
> > +constexpr B &&b2 { { 3 }, { 4 } }; // expected-note {{temporary created
> here}}
> > +static_assert(&b1 != &b2, "");
> > +static_assert(&b1.a1 != &b2.a1, ""); // expected-error {{constant
> expression}} expected-note {{outside the expression that created the
> temporary}}
> > +
> > +constexpr thread_local B b3 { { 1 }, { 2 } }; // expected-error
> {{constant expression}} expected-note {{reference to temporary}}
> expected-note {{here}}
> > +void foo() {
> > + constexpr static B b1 { { 1 }, { 2 } }; // ok
> > + constexpr thread_local B b2 { { 1 }, { 2 } }; // expected-error
> {{constant expression}} expected-note {{reference to temporary}}
> expected-note {{here}}
> > + constexpr B b3 { { 1 }, { 2 } }; // expected-error {{constant
> expression}} expected-note {{reference to temporary}} expected-note {{here}}
> > +}
> > +
> > +constexpr B &&b4 = ((1, 2), 3, 4, B { {10}, {{20}} }); //
> expected-warning 4{{unused}}
> > +static_assert(&b4 != &b2, "");
> > +
> > +// Proposed DR: copy-elision doesn't trigger lifetime extension.
> > +constexpr B b5 = B{ {0}, {0} }; // expected-error {{constant
> expression}} expected-note {{reference to temporary}} expected-note {{here}}
> > +
> > }
> >
> > constexpr int strcmp_ce(const char *p, const char *q) {
> > @@ -572,7 +596,7 @@ struct E {
> > constexpr E() : p(&p) {}
> > void *p;
> > };
> > -constexpr const E &e1 = E(); // expected-error {{constant expression}}
> expected-note {{reference to temporary is not a constant expression}}
> expected-note {{temporary created here}}
> > +constexpr const E &e1 = E();
> > // This is a constant expression if we elide the copy constructor call,
> and
> > // is not a constant expression if we don't! But we do, so it is.
> > constexpr E e2 = E();
> > @@ -1282,8 +1306,23 @@ struct Wrap {
> > constexpr const Wrap &g(const Wrap &w) { return w; }
> > constexpr int k2 = g({0}).value; // ok
> >
> > -constexpr const int &i = 0; // expected-error {{constant expression}}
> expected-note {{temporary}} expected-note 2{{here}}
> > -constexpr const int j = i; // expected-error {{constant expression}}
> expected-note {{initializer of 'i' is not a constant expression}}
> > +// The temporary here has static storage duration, so we can bind a
> constexpr
> > +// reference to it.
> > +constexpr const int &i = 1;
> > +constexpr const int j = i;
> > +static_assert(j == 1, "");
> > +
> > +// The temporary here is not const, so it can't be read outside the
> expression
> > +// in which it was created (per the C++14 rules, which we use to avoid
> a C++11
> > +// defect).
> > +constexpr int &&k = 1; // expected-note {{temporary created here}}
> > +constexpr const int l = k; // expected-error {{constant expression}}
> expected-note {{read of temporary}}
> > +
> > +void f() {
> > + // The temporary here has automatic storage duration, so we can't
> bind a
> > + // constexpr reference to it.
> > + constexpr const int &i = 1; // expected-error {{constant expression}}
> expected-note 2{{temporary}}
> > +}
> >
> > }
> >
> >
> > Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=183283&r1=183282&r2=183283&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)
> > +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Tue Jun 4
> 19:46:14 2013
> > @@ -715,3 +715,13 @@ namespace deduced_return_type {
> > static_assert(f() == 0, "");
> > static_assert(g(true), "");
> > }
> > +
> > +namespace modify_temporary_during_construction {
> > + struct A { int &&temporary; int x; int y; };
> > + constexpr int f(int &r) { r *= 9; return r - 12; }
> > + // FIXME: The 'uninitialized' warning here is bogus.
> > + constexpr A a = { 6, f(a.temporary), a.temporary }; //
> expected-warning {{uninitialized}} expected-note {{temporary created here}}
> > + static_assert(a.x == 42, "");
> > + static_assert(a.y == 54, "");
> > + constexpr int k = a.temporary++; // expected-error {{constant
> expression}} expected-note {{outside the expression that created the
> temporary}}
> > +}
> >
> >
> > _______________________________________________
> > cfe-commits mailing list
> > cfe-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130604/70e95c0a/attachment.html>
More information about the cfe-commits
mailing list