Topic: [c++std-ext-14644] A prototype implementation
Author: John Spicer <jhs@edg.com>
Date: Wed, 27 Nov 2013 16:47:13 -0500
Raw View
--Apple-Mail=_EA527F19-5E1F-424B-AA56-EC0F24ABC911
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1
I have to say that the more this is discussed, the more I think we should n=
ot make a change to allow this use of auto.
It introduces a significant set of special cases, which require a lot more =
to understand than the simple prohibition of auto in that context.
It also changes the rules for when NSDMIs are instantiated in class templat=
es, which seems like an unfortunate interaction.
It seems like a lot of added complexity for users for what is, in my opinio=
n, a minimal benefit.
John.
On Nov 27, 2013, at 4:22 PM, Faisal Vali <faisalv@gmail.com> wrote:
>=20
>=20
> On Wed, Nov 27, 2013 at 2:54 PM, Richard Smith <richard@metafoo.co.uk> wr=
ote:
> On Wed, Nov 27, 2013 at 11:13 AM, Faisal Vali <faisalv@gmail.com> wrote:
> Hi,
> Since interest in and concerns about allowing 'auto' non static data me=
mbers has been expressed (http://accu.org/cgi-bin/wg21/message?wg=3Dcore&ms=
g=3D23223 & http://accu.org/cgi-bin/wg21/message?wg=3Dcore&msg=3D23496) - I=
thought I'd hack together a quick implementation (based entirely on Richar=
d smith's Idea: http://accu.org/cgi-bin/wg21/message?wg=3Dext&msg=3D14418) =
to get a better sense of some of the challenges.
>=20
> What I've managed to kludge so far (and I make no claims of correctness o=
r viability of the approach since neither Richard nor Doug have had a chanc=
e to review the code) is here:
> - https://github.com/faisalv/clang/commits/auto-nsdmi-llvm-r195138%2811=
-19-13%29
>=20
> As Richard had suggested in his post, all name lookup and type deduction =
for 'auto' is done at the closing brace (that is all class names have been =
seen). In the clang patch above, this is done just before some semantic c=
hecks are performed on all Field members and the class is marked "complete"=
(so layout can be calculated). The auto member's initializer is always pa=
rsed (albeit, delayed until the closing brace - but in templates this coul=
d result in a hard error even if the initializer is not used for initializa=
tion - but with clang this occurs even for non auto members, right?).
>=20
> It does, but per discussion in core, it should not -- default initializer=
s should only be instantiated when they're needed (see core issue 1396). I =
don't see a problem with eagerly instantiating them when we complete the cl=
ass, for each non-static data member whose type contains a placeholder.
> =20
> The test file (to get a sense of the constructs that work) is here:=20
> https://github.com/faisalv/clang/blob/auto-nsdmi-llvm-r195138%2811-19-13%=
29/test/SemaCXX/cxx1z-auto-nsdmi.cpp
>=20
> Essentially, things you can NOT do in the auto NSDMI
> - use sizeof/alignof on the class being defined
> - create an object of the type being defined
> - refer to any auto members in in-class static member initializers (cla=
ss is not complete in them)
> - refer to one auto member before its lexical definition in another aut=
o member's initializer, or in areas where the class is not marked-complete =
(decltype within member function return types).
> - refer to any member functions with deduced return types (although in =
clang you can not do this in non-auto members currently - is this a bug or =
do we intend to support:
> struct X { auto f() { return 0; } int i =3D f(); };
>=20
> This is a very messy area; the core language doesn't specify the circumst=
ances under which one delay-parsed entity can refer to another (this shows =
up in a number of other guises, such as calling a constexpr function in a c=
onstant expression in an exception specification, or calling a function wit=
h a deduced return type in a default argument). Last time I looked at this,=
each compiler did something different here. This seems worthy of a core is=
sue.
> =20
> Stuff you can do as long as you don't violate the above:
> - refer to other members/mem_funs defined before or after the auto memb=
er=20
> - capture 'this' in class-level lambdas.
> =20
> For e.g. the following works:
> struct X { //expected-note{{implicit default constructor}}
> auto a1 =3D sizeof(this);
> auto& self =3D *this;
> auto a2 =3D this->mem; //expected-warning {{uninitialized}}
> auto *a3 =3D this;
> auto a4 =3D a3;
> auto a5 =3D mem_fun(); // double
> auto a6 =3D const_cast<const X*>(this)->mem_fun(); // char =20
> auto L =3D [this, &r =3D *this, p =3D this] (auto a) {=20
> return r(a, this->self, p->a2);=20
> };
> auto a7 =3D ([=3D](auto a) { return a->a1 + a1; })(this);
> auto L2 =3D [=3D](auto a) { return self(a, *this, 3); };
> int mem =3D 5;
> double mem_fun() { return 3.14; }
> char mem_fun() const { return 'a'; }
> template<class T> bool operator()(T t, X&, int) { return true; }
> };
>=20
> I am quite confident there are bugs, and issues I have not thought about =
- but I just wanted to see where Richard's idea could start to take us.
>=20
> Is the class regarded as complete when you parse the default initializers=
? If so, what happens if one of them requires knowledge of the class layout=
? For instance:
>=20
>=20
> It is regarded as complete for purposes of layout when you parse non auto=
default initializers - but not complete for purposes of layout when you ar=
e parsing default initializers for auto members (although the sema::ActOnCX=
XInClassMemberInitializer hook, which checks the initialization conversions=
, lval-to-rval etc. is done once the class is marked complete, with the res=
t of the fields, in the order they were all declared).
>=20
> =20
> template<int> struct something { typedef int type; };
>=20
> struct A {
> int x;
> auto y =3D something<offsetof(A, z)>::type(); // will need layout here
> int z;
> };
>=20
> ... or ...
>=20
> template<int*> struct something { typedef int type; };
>=20
> template<typename T> auto stuff() {
> static T t;
> constexpr int *p =3D &t.z; // may need layout here
> return typename something<p>::type();
> }
>=20
> struct A {
> int x;
> auto y =3D stuff<A>();
> int z;
> };
>=20
>=20
> Your examples generate the following error messages:
> template<int*> struct something { typedef int type; };
>=20
> template<typename T> auto stuff() {
> static T t; //expected-error{{incomplete type}}
> constexpr int *p =3D &t.z; // may need layout here
> return typename something<p>::type();
> }
>=20
> struct A { //expected-note{{not complete}}
> int x;
> auto y =3D stuff<A>(); //expected-note{{instantiation}}
> int z;
> };
> namespace offsetof_test {
>=20
> #define offsetof(t, d) __builtin_offsetof(t, d)=20
>=20
> template<int> struct something { typedef int type; };
>=20
> struct A { //expected-note{{not complete}}
> int x;
> auto y =3D something<offsetof(A, z)>::type{}; //expected-error{{incompl=
ete type}}\
> //expected-error{{expected ';'}}
> int z;
> };
>=20
> }
>=20
> thanks!
>=20
>=20
> =20
> Any thoughts on whether it is worth spending more time on this? Any conce=
rns about this direction? Any obvious cases that have been overlooked? Is t=
here enough interest to warrant a paper (would anyone be willing to help wr=
ite one if that is the case?)
>=20
> Thanks!
>=20
> Faisal Vali
>=20
> [I believe this certainly increases the potential for ODR-violations - bu=
t last i heard, google was toying around with the idea of a static-analysis=
tool to detect odr-violations? http://clang-developers.42468.n3.nabble.com=
/design-for-an-accurate-ODR-checker-with-clang-td4033150.html any updates o=
n this?]. =20
>=20
> --=20
> =20
> ---=20
> You received this message because you are subscribed to the Google Groups=
"ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an=
email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at http://groups.google.com/a/isocpp.org/group/std-propo=
sals/.
>=20
>=20
> --=20
> =20
> ---=20
> You received this message because you are subscribed to the Google Groups=
"ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an=
email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at http://groups.google.com/a/isocpp.org/group/std-propo=
sals/.
>=20
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--Apple-Mail=_EA527F19-5E1F-424B-AA56-EC0F24ABC911
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Diso-8859-1"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mo=
de: space; -webkit-line-break: after-white-space; "><div>I have to say that=
the more this is discussed, the more I think we should not make a change t=
o allow this use of auto.</div><div><br></div><div>It introduces a signific=
ant set of special cases, which require a lot more to understand than the s=
imple prohibition of auto in that context.</div><div><br></div><div>It also=
changes the rules for when NSDMIs are instantiated in class templates, whi=
ch seems like an unfortunate interaction.</div><div><br></div><div>It seems=
like a lot of added complexity for users for what is, in my opinion, a min=
imal benefit.</div><div><br></div><div>John.</div><div><br></div><br><div><=
div>On Nov 27, 2013, at 4:22 PM, Faisal Vali <<a href=3D"mailto:faisalv@=
gmail.com">faisalv@gmail.com</a>> wrote:</div><br class=3D"Apple-interch=
ange-newline"><blockquote type=3D"cite"><div dir=3D"ltr"><br><div class=3D"=
gmail_extra"><br><div class=3D"gmail_quote">On Wed, Nov 27, 2013 at 2:54 PM=
, Richard Smith <span dir=3D"ltr"><<a href=3D"mailto:richard@metafoo.co.=
uk" target=3D"_blank">richard@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div cla=
ss=3D"im">On Wed, Nov 27, 2013 at 11:13 AM, Faisal Vali <span dir=3D"ltr">&=
lt;<a href=3D"mailto:faisalv@gmail.com" target=3D"_blank">faisalv@gmail.com=
</a>></span> wrote:<br>
</div><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div class=3D"i=
m">
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">Hi,<br>&=
nbsp; Since interest in and concerns about allowing 'auto' non static data =
members has been expressed (<a href=3D"http://accu.org/cgi-bin/wg21/message=
?wg=3Dcore&msg=3D23223" target=3D"_blank">http://accu.org/cgi-bin/wg21/=
message?wg=3Dcore&msg=3D23223</a> & <a href=3D"http://accu.org/cgi-=
bin/wg21/message?wg=3Dcore&msg=3D23496" target=3D"_blank">http://accu.o=
rg/cgi-bin/wg21/message?wg=3Dcore&msg=3D23496</a>) - I thought I'd hack=
together a quick implementation (based entirely on Richard smith's Idea: <=
a href=3D"http://accu.org/cgi-bin/wg21/message?wg=3Dext&msg=3D14418" ta=
rget=3D"_blank">http://accu.org/cgi-bin/wg21/message?wg=3Dext&msg=3D144=
18</a>) to get a better sense of some of the challenges.<br>
<div><br></div>
<div>What I've managed to kludge so far (and I make no claims of correctnes=
s or viability of the approach since neither Richard nor Doug have had a ch=
ance to review the code) is here:<br> - <a href=3D"https://github.com=
/faisalv/clang/commits/auto-nsdmi-llvm-r195138%2811-19-13%29" target=3D"_bl=
ank">https://github.com/faisalv/clang/commits/auto-nsdmi-llvm-r195138%2811-=
19-13%29</a><br>
<br></div>
<div>As Richard had suggested in his post, all name lookup and type deducti=
on for 'auto' is done at the closing brace (that is all class names have be=
en seen). In the clang patch above, this is done just before some se=
mantic checks are performed on all Field members and the class is marked "c=
omplete" (so layout can be calculated). The auto member's initializer=
is always parsed (albeit, delayed until the closing brace - but in t=
emplates this could result in a hard error even if the initializer is not u=
sed for initialization - but with clang this occurs even for non auto membe=
rs, right?).<br>
</div></div></blockquote><div><br></div></div><div>It does, but per discuss=
ion in core, it should not -- default initializers should only be instantia=
ted when they're needed (see core issue 1396). I don't see a problem with e=
agerly instantiating them when we complete the class, for each non-static d=
ata member whose type contains a placeholder.</div>
<div class=3D"im">
<div> </div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr">The test file (to get a sense of the constructs that work) is here=
: <br>
<a href=3D"https://github.com/faisalv/clang/blob/auto-nsdmi-llvm-r195138%28=
11-19-13%29/test/SemaCXX/cxx1z-auto-nsdmi.cpp" target=3D"_blank">https://gi=
thub.com/faisalv/clang/blob/auto-nsdmi-llvm-r195138%2811-19-13%29/test/Sema=
CXX/cxx1z-auto-nsdmi.cpp</a><br>
<br>
<div>Essentially, things you can NOT do in the auto NSDMI<br></div>
<div> - use sizeof/alignof on the class being defined</div>
<div> - create an object of the type being defined<br></div>
<div> - refer to any auto members in in-class static member initializ=
ers (class is not complete in them)<br> - refer to one auto member be=
fore its lexical definition in another auto member's initializer, or in are=
as where the class is not marked-complete (decltype within member function =
return types).<br>
- refer to any member functions with deduced return types (although =
in clang you can not do this in non-auto members currently - is this a bug =
or do we intend to support:</div>
<div> struct X { auto f() { return 0; } int i =3D f=
(); };</div></div></blockquote><div><br></div></div><div>This is a very mes=
sy area; the core language doesn't specify the circumstances under which on=
e delay-parsed entity can refer to another (this shows up in a number of ot=
her guises, such as calling a constexpr function in a constant expression i=
n an exception specification, or calling a function with a deduced return t=
ype in a default argument). Last time I looked at this, each compiler did s=
omething different here. This seems worthy of a core issue.</div>
<div class=3D"im">
<div> </div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div>Stuff you can do as long as you don't violate the above:<br>
</div>
<div> - refer to other members/mem_funs defined before or after =
the auto member </div>
<div> - capture 'this' in class-level lambdas.</div>
<div> </div>
<div>For e.g. the following works:</div>
<div> struct X { //expected-note{{implicit default constructor}}<br>&n=
bsp; auto a1 =3D sizeof(this);<br> auto& =
self =3D *this;<br> auto a2 =3D this->mem; //expected-=
warning {{uninitialized}}<br> auto *a3 =3D this;<br>
auto a4 =3D a3;<br> auto a5 =3D mem_fu=
n(); // double<br> auto a6 =3D const_cast<const X*>=
(this)->mem_fun(); // char <br> auto L =3D=
[this, &r =3D *this, p =3D this] (auto a) { <br> &nbs=
p; return r(a, this->self, p->a2)=
; <br>
};<br> auto a7 =3D ([=3D](auto a) { re=
turn a->a1 + a1; })(this);<br> auto L2 =3D [=3D](auto =
a) { return self(a, *this, 3); };<br> int mem =3D 5;<br>&=
nbsp; double mem_fun() { return 3.14; }<br> c=
har mem_fun() const { return 'a'; }<br>
template<class T> bool operator()(T t, X&, int=
) { return true; }<br> };<br><br></div><div>I am quite confident ther=
e are bugs, and issues I have not thought about - but I just wanted to see =
where Richard's idea could start to take us.<br>
</div></div></blockquote><div><br></div></div><div>Is the class regarded as=
complete when you parse the default initializers? If so, what happens if o=
ne of them requires knowledge of the class layout? For instance:</div>
<div>
<br></div></div></div></div></blockquote><div><br></div><div>It is regarded=
as complete for purposes of layout when you parse non auto default initial=
izers - but not complete for purposes of layout when you are parsing defaul=
t initializers for auto members (although the sema::ActOnCXXInClassMemberIn=
itializer hook, which checks the initialization conversions, lval-to-rval e=
tc. is done once the class is marked complete, with the rest of the fields,=
in the order they were all declared).<br>
</div><div><br> </div><blockquote class=3D"gmail_quote" style=3D"margi=
n:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex=
"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><d=
iv></div><div>
template<int> struct something { typedef int type; };</div><div><br><=
/div><div>struct A {</div><div> int x;</div><div> auto y =3D so=
mething<offsetof(A, z)>::type(); // will need layout here</div>
<div> int z;</div><div>};</div><div><br></div><div>... or ...</div><d=
iv><br></div><div>template<int*> struct something { typedef int type;=
};</div><div><br></div><div>template<typename T> auto stuff() {</div=
>
<div> static T t;</div><div> constexpr int *p =3D &t.z; // =
may need layout here</div><div> return typename something<p>::t=
ype();</div><div>}</div><div><br></div><div>struct A {</div><div> int=
x;</div><div> auto y =3D stuff<A>();</div>
<div> int z;<br>};</div><div><br></div></div></div></div></blockquote=
><div><br></div><div>Your examples generate the following error messages:<b=
r>template<int*> struct something { typedef int type; };<br><br>templ=
ate<typename T> auto stuff() {<br>
static T t; //expected-error{{incomplete type}}<br> cons=
texpr int *p =3D &t.z; // may need layout here<br> return typenam=
e something<p>::type();<br>}<br><br>struct A { //expected-note{{not c=
omplete}}<br> int x;<br>
auto y =3D stuff<A>(); //expected-note{{instantiation}}<br>&nb=
sp; int z;<br>};<br>namespace offsetof_test {<br><br>#define offsetof(t,&nb=
sp; d) __builtin_offsetof(t, d) <br><br>template<int> struct somethin=
g { typedef int type; };<br>
<br>struct A { //expected-note{{not complete}}<br> int x;<br> a=
uto y =3D something<offsetof(A, z)>::type{}; //expected-error{{incomp=
lete type}}\<br> //expected-error=
{{expected ';'}}<br> int z;<br>};<br>
<br>}<br></div><div><br></div><div>thanks!<br></div><div><br><br> </di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div c=
lass=3D"gmail_extra">
<div class=3D"gmail_quote"><div></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
ng-left:1ex"><div class=3D"im"><div dir=3D"ltr"><div>
<div>Any thoughts on whether it is worth spending more time on this? Any co=
ncerns about this direction? Any obvious cases that have been overlooked? I=
s there enough interest to warrant a paper (would anyone be willing to help=
write one if that is the case?)<br>
</div><br></div><div>Thanks!<br></div>
<div><br></div>
<div>
<div>Faisal Vali<br><br>[I believe this certainly increases the potential f=
or ODR-violations
- but last i heard, google was toying around with the idea of a=20
static-analysis tool to detect odr-violations? <a href=3D"http://clang-deve=
lopers.42468.n3.nabble.com/design-for-an-accurate-ODR-checker-with-clang-td=
4033150.html" target=3D"_blank">http://clang-developers.42468.n3.nabble.com=
/design-for-an-accurate-ODR-checker-with-clang-td4033150.html</a> any updat=
es on this?]. <br>
<span><font color=3D"#888888">
</font></span></div></div></div></div><span><font color=3D"#888888"><div><b=
r class=3D"webkit-block-placeholder"></div>
-- <br><div class=3D"im">
<br>
--- <br>
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</div></font></span></blockquote></div><br></div></div><div class=3D""><div=
class=3D"h5"><div><br class=3D"webkit-block-placeholder"></div>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</div></div></blockquote></div><br></div></div>
</blockquote></div><br></body></html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_EA527F19-5E1F-424B-AA56-EC0F24ABC911--
.