Message ID | ZdR2yw+J89YmCw50@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Fix explicit instantiation of const variable templates after earlier implicit instantation [PR113976] | expand |
On Tue, 20 Feb 2024, Jakub Jelinek wrote: > Hi! > > Already previously instantiated const variable templates had > cp_apply_type_quals_to_decl called when they were instantiated, > but if they need runtime initialization, their TREE_READONLY flag > has been subsequently cleared. > Explicit variable template instantiation calls grokdeclarator which > calls cp_apply_type_quals_to_decl on them again, setting TREE_READONLY > flag again, but nothing clears it afterwards, so we emit such > instantiations into rodata sections and segfault when the dynamic > initialization attempts to initialize them. > > The following patch fixes that by not calling cp_apply_type_quals_to_decl > on already instantiated variable declarations. LGTM, this seems like the safest approach for backporting. Note we can't check DECL_EXPLICIT_INSTANTIATION at this point because that doesn't get set until later from do_decl_instantiation. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2024-02-19 Jakub Jelinek <jakub@redhat.com> > Patrick Palka <ppalka@redhat.com> > > PR c++/113976 > * decl.cc (grokdeclarator): Don't call cp_apply_type_quals_to_decl > on DECL_TEMPLATE_INSTANTIATED VAR_DECLs. > > * g++.dg/cpp1y/var-templ87.C: New test. > > --- gcc/cp/decl.cc.jj 2024-02-15 09:51:34.460065992 +0100 > +++ gcc/cp/decl.cc 2024-02-19 19:18:09.839188137 +0100 > @@ -15263,7 +15263,12 @@ grokdeclarator (const cp_declarator *dec > /* Record constancy and volatility on the DECL itself . There's > no need to do this when processing a template; we'll do this > for the instantiated declaration based on the type of DECL. */ > - if (!processing_template_decl) > + if (!processing_template_decl > + /* Don't do it for instantiated variable templates either, > + cp_apply_type_quals_to_decl should have been called on it > + already and might have been overridden in cp_finish_decl > + if initializer needs runtime initialization. */ > + && (!VAR_P (decl) || !DECL_TEMPLATE_INSTANTIATED (decl))) > cp_apply_type_quals_to_decl (type_quals, decl); > > return decl; > --- gcc/testsuite/g++.dg/cpp1y/var-templ87.C.jj 2024-02-19 19:21:49.668129195 +0100 > +++ gcc/testsuite/g++.dg/cpp1y/var-templ87.C 2024-02-19 19:21:42.218232862 +0100 > @@ -0,0 +1,43 @@ > +// PR c++/113976 > +// { dg-do run { target c++14 } } > + > +int > +foo () > +{ > + return 42; > +} > + > +template <int N> > +const int a = foo (); > +const int *b = &a <0>; > +template <int N> > +const int c = foo (); > +template const int c <0>; > +template <int N> > +const int d = foo (); > +const int *e = &d <0>; > +template const int d <0>; > +template <int N> > +const int f = foo (); > +template const int f <0>; > +const int *g = &f <0>; > +struct S { int a, b; }; > +template <int N> > +const S h = { 42, foo () }; > +const S *i = &h <0>; > +template <int N> > +const S j = { 42, foo () }; > +template const S j <0>; > +template <int N> > +const S k = { 42, foo () }; > +const S *l = &k <0>; > +template const S k <0>; > +template <int N> > +const S m = { 42, foo () }; > +template const S m <0>; > +const S *n = &m <0>; > + > +int > +main () > +{ > +} > > Jakub > >
On 2/26/24 12:10, Patrick Palka wrote: > On Tue, 20 Feb 2024, Jakub Jelinek wrote: > >> Hi! >> >> Already previously instantiated const variable templates had >> cp_apply_type_quals_to_decl called when they were instantiated, >> but if they need runtime initialization, their TREE_READONLY flag >> has been subsequently cleared. >> Explicit variable template instantiation calls grokdeclarator which >> calls cp_apply_type_quals_to_decl on them again, setting TREE_READONLY >> flag again, but nothing clears it afterwards, so we emit such >> instantiations into rodata sections and segfault when the dynamic >> initialization attempts to initialize them. >> >> The following patch fixes that by not calling cp_apply_type_quals_to_decl >> on already instantiated variable declarations. > > LGTM, this seems like the safest approach for backporting. Note > we can't check DECL_EXPLICIT_INSTANTIATION at this point because > that doesn't get set until later from do_decl_instantiation. Agreed, OK.
--- gcc/cp/decl.cc.jj 2024-02-15 09:51:34.460065992 +0100 +++ gcc/cp/decl.cc 2024-02-19 19:18:09.839188137 +0100 @@ -15263,7 +15263,12 @@ grokdeclarator (const cp_declarator *dec /* Record constancy and volatility on the DECL itself . There's no need to do this when processing a template; we'll do this for the instantiated declaration based on the type of DECL. */ - if (!processing_template_decl) + if (!processing_template_decl + /* Don't do it for instantiated variable templates either, + cp_apply_type_quals_to_decl should have been called on it + already and might have been overridden in cp_finish_decl + if initializer needs runtime initialization. */ + && (!VAR_P (decl) || !DECL_TEMPLATE_INSTANTIATED (decl))) cp_apply_type_quals_to_decl (type_quals, decl); return decl; --- gcc/testsuite/g++.dg/cpp1y/var-templ87.C.jj 2024-02-19 19:21:49.668129195 +0100 +++ gcc/testsuite/g++.dg/cpp1y/var-templ87.C 2024-02-19 19:21:42.218232862 +0100 @@ -0,0 +1,43 @@ +// PR c++/113976 +// { dg-do run { target c++14 } } + +int +foo () +{ + return 42; +} + +template <int N> +const int a = foo (); +const int *b = &a <0>; +template <int N> +const int c = foo (); +template const int c <0>; +template <int N> +const int d = foo (); +const int *e = &d <0>; +template const int d <0>; +template <int N> +const int f = foo (); +template const int f <0>; +const int *g = &f <0>; +struct S { int a, b; }; +template <int N> +const S h = { 42, foo () }; +const S *i = &h <0>; +template <int N> +const S j = { 42, foo () }; +template const S j <0>; +template <int N> +const S k = { 42, foo () }; +const S *l = &k <0>; +template const S k <0>; +template <int N> +const S m = { 42, foo () }; +template const S m <0>; +const S *n = &m <0>; + +int +main () +{ +}