<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Jul 1, 2013 at 7:37 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class=""><div class="h5">On Mon, Jul 1, 2013 at 7:34 PM, Eli Friedman <<a href="mailto:eli.friedman@gmail.com">eli.friedman@gmail.com</a>> wrote:<br>
> On Mon, Jul 1, 2013 at 7:05 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
>><br>
>> On Mon, Jul 1, 2013 at 3:53 PM, Eli Friedman <<a href="mailto:eli.friedman@gmail.com">eli.friedman@gmail.com</a>><br>
>> wrote:<br>
>> > On Mon, Jul 1, 2013 at 3:42 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>><br>
>> > wrote:<br>
>> >><br>
>> >> On Sun, Jun 30, 2013 at 6:39 PM, Eli Friedman <<a href="mailto:eli.friedman@gmail.com">eli.friedman@gmail.com</a>><br>
>> >> wrote:<br>
>> >> > On Tue, Jun 4, 2013 at 5:46 PM, Richard Smith<br>
>> >> > <<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>><br>
>> >> > 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<br>
>> >> >> model<br>
>> >> >> to<br>
>> >> >> handle temporaries which have been lifetime-extended to static<br>
>> >> >> storage<br>
>> >> >> duration<br>
>> >> >> within constant expressions. This correctly handles nested lifetime<br>
>> >> >> extension<br>
>> >> >> (through reference members of aggregates in aggregate initializers)<br>
>> >> >> but<br>
>> >> >> non-constant-expression emission hasn't yet been updated to do the<br>
>> >> >> 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>
>> >> >><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:<br>
>> >> >><br>
>> >> >><br>
>> >> >> <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>
>> >> >><br>
>> >> >><br>
>> >> >> ==============================================================================<br>
>> >> >> --- cfe/trunk/include/clang/AST/ASTContext.h (original)<br>
>> >> >> +++ cfe/trunk/include/clang/AST/ASTContext.h Tue Jun 4 19:46:14<br>
>> >> >> 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<br>
>> >> >> storage<br>
>> >> >> duration<br>
>> >> >> + /// that appear in constant initializers to their evaluated<br>
>> >> >> values.<br>
>> >> >> + llvm::DenseMap<const MaterializeTemporaryExpr*, APValue><br>
>> >> >> + MaterializedTemporaryValues;<br>
>> >> >> +<br>
>> >> >> /// \brief Representation of a "canonical" template template<br>
>> >> >> parameter<br>
>> >> >> that<br>
>> >> >> /// is used in canonical template names.<br>
>> >> >> class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode<br>
>> >> >> {<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<br>
>> >> >> bitfield.<br>
>> >> >> unsigned getParameterIndex(const ParmVarDecl *D) const;<br>
>> >> >> -<br>
>> >> >> +<br>
>> >> >> + /// \brief Get the storage for the constant value of a<br>
>> >> >> materialized<br>
>> >> >> temporary<br>
>> >> >> + /// of static storage duration.<br>
>> >> >> + APValue *getMaterializedTemporaryValue(const<br>
>> >> >> MaterializeTemporaryExpr<br>
>> >> >> *E,<br>
>> >> >> + bool MayCreate);<br>
>> >> >><br>
>> >> ><br>
>> >> > Having a global table of temporary values seems really fragile given<br>
>> >> > the<br>
>> >> > ability to modify the values of the temporaries in C++1y.<br>
>> >> > (const-init-cxx1y.cpp happens to work given the precise order we call<br>
>> >> > into<br>
>> >> > the constant evaluator, but could easily break if we change how we do<br>
>> >> > CodeGen.) Have you given any thought to this?<br>
>> >><br>
>> >> Yes; I'm also not entirely happy with the current state of affairs.<br>
>> >><br>
>> >> The best approach I've thought of to improve the situation is to<br>
>> >> ensure the ASTContext storage is only used when evaluating the<br>
>> >> initializer for the variable that lifetime-extends the temporary (that<br>
>> >> is, refuse to evaluate the temporary otherwise, and clear out all the<br>
>> >> storage for the variable's extended temporaries if the overall<br>
>> >> evaluation fails). It's not possible for us to emit a reference to a<br>
>> >> MaterializeTemporaryExpr from outside the variable's initializer if<br>
>> >> we've not succeeded in evaluating its initializer, so we shouldn't<br>
>> >> emit it with the "wrong" initializer.<br>
>> >><br>
>> >> In addition, we should probably move the code that emits the constant<br>
>> >> in the ASTContext storage from GetAddrOfGlobalTemporary into<br>
>> >> CGExprConstant, so that we can more aggressively assert that we get<br>
>> >> this right.<br>
>> >><br>
>> >> This would still be a little untidy. Do you have a better suggestion?<br>
>> ><br>
>> ><br>
>> > This might be a bit crazy, but have you considered extending APValue?<br>
>> > Specifically, we could add a new kind of LValue whose base is a<br>
>> > temporary<br>
>> > with the given value. That way, when CGExprConstant is doing<br>
>> > evaluation,<br>
>> > the value is right there, instead of messing with a global table.<br>
>><br>
>> We'd need all the LValues pointing at the same temporary to share the<br>
>> same value; that risks misbehavior if we evaluate the initializer for<br>
>> a variable multiple times for whatever reason,<br>
><br>
><br>
> I'm not sure why this is an issue; as long as the LValue in question<br>
> represents a reference temporary with the same mangled name and the same<br>
> value, it doesn't really matter how many instances of it exist.<br>
<br>
</div></div>Sure, but not all LValues referring to the temporary will have the<br>
same value during evaluation if we evaluate the initializer multiple<br>
times and it modifies the temporary.<br></blockquote><div><br></div><div>Ah, right.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="im"><br>
>> but I think it can be<br>
>> made to work. The semantic model feels a bit strange; the initial<br>
>> value for a global temporary really is a global thing, and shouldn't<br>
>> depend on how you constructed the LValue referring to it.<br>
><br>
><br>
> I think that's just the nature of the C++1y model.<br>
<br>
</div>I'm not sure I understand what you mean. Under the C++1y model, the<br>
value of the temporary can only change while you're evaluating the<br>
initializer of the surrounding declaration. The value is a global<br>
property, and doesn't depend on how you constructed the lvalue.<br>
</blockquote></div><br>Well, the theoretical model is that either the whole global is evaluated at compile-time, or the whole global including global temporaries are zero-initialized and evaluated at runtime. That's not very strange at all. That said, as an optimization, we currently try to pre-evaluate the global temporaries produced by a global even when we can't evaluate the whole global. Including that in your mental model makes things seem weirder than they actually are.<br>
<br></div><div class="gmail_extra">-Eli<br></div></div>