Message ID | 82a3fdf8-74ac-a15e-d1ef-b85782b6055f@oracle.com |
---|---|
State | New |
Headers | show |
OK. On Fri, Mar 10, 2017 at 5:38 PM, Paolo Carlini <paolo.carlini@oracle.com> wrote: > Hi, > > On 10/03/2017 16:57, Jason Merrill wrote: >> >> On Fri, Mar 10, 2017 at 9:58 AM, Paolo Carlini <paolo.carlini@oracle.com> >> wrote: >>> >>> As such, the broken declaration cannot be rejected by the code we have in >>> finish_struct, something must happen earlier than that. It seems to me >>> that >>> xref_tag_1 can be a good place, per the below patchlet, which passes >>> testing >>> on x86_64-linux. I briefly wondered if making is_std_init_list stricter >>> would make sense instead, but I don't think so (consistently with the >>> trail >>> of c++/60848 too): I believe that by the time we use is_std_init_list in >>> the >>> internals we want something as simple as possible, we are assuming that >>> broken, fake, std::initializer_list aren't around in the translation >>> unit. >>> In terms of details, I also wondered if CLASSTYPE_IS_TEMPLATE would make >>> for >>> a better check, but seems unnecessarily more complex. Also, in principle, >>> we >>> may want to have an even stricter check at declaration time (how many >>> template parameters, etc) but that seems overkilling and I don't think we >>> are risking ICEs because of that. >> >> I agree with all of this. How about in pushtag_1 instead, where we >> can return error_mark_node instead of aborting? > > Sure. In that case the testcase for that older issue also requires > adjusting. The below passes testing, anyway. > > Thanks, > Paolo. > > ////////////////////
Index: cp/name-lookup.c =================================================================== --- cp/name-lookup.c (revision 246023) +++ cp/name-lookup.c (working copy) @@ -6207,6 +6207,15 @@ pushtag_1 (tree name, tree type, tag_scope scope) decl = pushdecl_with_scope_1 (decl, b, /*is_friend=*/false); if (decl == error_mark_node) return decl; + + if (DECL_CONTEXT (decl) == std_node + && strcmp (TYPE_NAME_STRING (type), "initializer_list") == 0 + && !CLASSTYPE_TEMPLATE_INFO (type)) + { + error ("declaration of std::initializer_list does not match " + "#include <initializer_list>, isn't a template"); + return error_mark_node; + } } if (! in_class) Index: testsuite/g++.dg/cpp0x/initlist85.C =================================================================== --- testsuite/g++.dg/cpp0x/initlist85.C (revision 246023) +++ testsuite/g++.dg/cpp0x/initlist85.C (working copy) @@ -3,7 +3,7 @@ namespace std { - struct initializer_list {}; // { dg-message "initializer_list" } + struct initializer_list {}; // { dg-error "declaration" } } void foo(std::initializer_list &); @@ -10,7 +10,5 @@ void foo(std::initializer_list &); void f() { - foo({1, 2}); + foo({1, 2}); // { dg-error "invalid initialization" } } - -// { dg-prune-output "compilation terminated" } Index: testsuite/g++.dg/cpp0x/initlist97.C =================================================================== --- testsuite/g++.dg/cpp0x/initlist97.C (revision 0) +++ testsuite/g++.dg/cpp0x/initlist97.C (working copy) @@ -0,0 +1,7 @@ +// PR c++/77752 +// { dg-do compile { target c++11 } } + +namespace std { + class initializer_list; // { dg-error "declaration" } +} +void f(std::initializer_list l) { f({2}); } // { dg-error "incomplete type" }