From 179e01085b0aed111ef1f7908c4b87c800f880e9 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 6 Mar 2025 18:26:37 +0100 Subject: [PATCH] c++: Update TYPE_FIELDS of variant types if cp_parser_late_parsing_default_args etc. modify it [PR98533] The following testcases ICE during type verification, because TYPE_FIELDS of e.g. S RECORD_TYPE in pr119123.C is different from TYPE_FIELDS of const S. Various decls are added to S's TYPE_FIELDS first, then finish_struct indirectly calls fixup_type_variants to sync the variant copies. But later on cp_parser_class_specifier calls cp_parser_late_parsing_default_args and that apparently adds a lambda type (from default argument) to TYPE_FIELDS of S. Dunno if that is right or not, assuming it is right, the following patch fixes it by updating TYPE_FIELDS of variant types if there were any changes in the various functions cp_parser_class_specifier defers and calls on the outermost enclosing class. There was quite a lot of code repetition already before, so the patch uses a lambda to avoid the repetitions. To my surprise, in some of the contract testcases ( g++.dg/contracts/contracts-friend1.C g++.dg/contracts/contracts-nested-class1.C g++.dg/contracts/contracts-nested-class2.C g++.dg/contracts/contracts-redecl7.C g++.dg/contracts/contracts-redecl8.C ) it is actually setting class_type and pushing TRANSLATION_UNIT_DECL rather than some class types in some cases. Or should the lambda pushing into the containing class be somehow avoided? 2025-03-06 Jakub Jelinek PR c++/98533 PR c++/119123 * parser.cc (cp_parser_class_specifier): Update TYPE_FIELDS of variant types in case cp_parser_late_parsing_default_args etc. change TYPE_FIELDS on the main variant. Add switch_to_class lambda and use it to simplify repeated class switching code. * g++.dg/cpp0x/pr98533.C: New test. * g++.dg/cpp0x/pr119123.C: New test. --- gcc/cp/parser.cc | 63 ++++++++++++++------------- gcc/testsuite/g++.dg/cpp0x/pr119123.C | 10 +++++ gcc/testsuite/g++.dg/cpp0x/pr98533.C | 25 +++++++++++ 3 files changed, 68 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr119123.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr98533.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 69c27aa7b6e..489c00e0522 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -27718,6 +27718,7 @@ cp_parser_class_specifier (cp_parser* parser) { tree decl; tree class_type = NULL_TREE; + tree class_type_fields = NULL_TREE; tree pushed_scope = NULL_TREE; unsigned ix; cp_default_arg_entry *e; @@ -27731,6 +27732,33 @@ cp_parser_class_specifier (cp_parser* parser) vec_safe_truncate (unparsed_funs_with_definitions, 0); } + auto switch_to_class = [&] (tree t) + { + if (class_type != t) + { + /* cp_parser_late_parsing_default_args etc. could have changed + TYPE_FIELDS (class_type), propagate that to all variants. */ + if (class_type + && RECORD_OR_UNION_TYPE_P (class_type) + && TYPE_FIELDS (class_type) != class_type_fields) + for (tree variant = TYPE_NEXT_VARIANT (class_type); + variant; variant = TYPE_NEXT_VARIANT (variant)) + TYPE_FIELDS (variant) = TYPE_FIELDS (class_type); + if (pushed_scope) + pop_scope (pushed_scope); + class_type = t; + class_type_fields = NULL_TREE; + if (t) + { + if (RECORD_OR_UNION_TYPE_P (class_type)) + class_type_fields = TYPE_FIELDS (class_type); + pushed_scope = push_scope (class_type); + } + else + pushed_scope = NULL_TREE; + } + }; + /* In a first pass, parse default arguments to the functions. Then, in a second pass, parse the bodies of the functions. This two-phased approach handles cases like: @@ -27746,13 +27774,7 @@ cp_parser_class_specifier (cp_parser* parser) decl = e->decl; /* If there are default arguments that have not yet been processed, take care of them now. */ - if (class_type != e->class_type) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = e->class_type; - pushed_scope = push_scope (class_type); - } + switch_to_class (e->class_type); /* Make sure that any template parameters are in scope. */ maybe_begin_member_template_processing (decl); /* Parse the default argument expressions. */ @@ -27768,13 +27790,7 @@ cp_parser_class_specifier (cp_parser* parser) FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl) { tree ctx = DECL_CONTEXT (decl); - if (class_type != ctx) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = ctx; - pushed_scope = push_scope (class_type); - } + switch_to_class (ctx); tree def_parse = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)); def_parse = TREE_PURPOSE (def_parse); @@ -27830,13 +27846,7 @@ cp_parser_class_specifier (cp_parser* parser) FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) { tree ctx = type_context_for_name_lookup (decl); - if (class_type != ctx) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = ctx; - pushed_scope = push_scope (class_type); - } + switch_to_class (ctx); inject_this_parameter (class_type, TYPE_UNQUALIFIED); cp_parser_late_parsing_nsdmi (parser, decl); } @@ -27846,13 +27856,7 @@ cp_parser_class_specifier (cp_parser* parser) FOR_EACH_VEC_SAFE_ELT (unparsed_contracts, ix, decl) { tree ctx = DECL_CONTEXT (decl); - if (class_type != ctx) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = ctx; - pushed_scope = push_scope (class_type); - } + switch_to_class (ctx); temp_override cfd(current_function_decl, decl); @@ -27893,8 +27897,7 @@ cp_parser_class_specifier (cp_parser* parser) current_class_ptr = NULL_TREE; current_class_ref = NULL_TREE; - if (pushed_scope) - pop_scope (pushed_scope); + switch_to_class (NULL_TREE); /* Now parse the body of the functions. */ if (flag_openmp) diff --git a/gcc/testsuite/g++.dg/cpp0x/pr119123.C b/gcc/testsuite/g++.dg/cpp0x/pr119123.C new file mode 100644 index 00000000000..bbc1ca0cf21 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr119123.C @@ -0,0 +1,10 @@ +// PR c++/119123 +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -g" } + +struct S { + template void foo (int = [] {}) const; +}; +struct T { + static void bar (const S &); +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/pr98533.C b/gcc/testsuite/g++.dg/cpp0x/pr98533.C new file mode 100644 index 00000000000..c279d021e19 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr98533.C @@ -0,0 +1,25 @@ +// PR c++/98533 +// { dg-do compile { target c++11 } } +// { dg-options "-g" } + +class IR; +struct Pass { + explicit Pass(IR *ir) : ir_(ir) {} + virtual ~Pass() = default; + IR *ir_ {nullptr}; +}; +struct PassManager { + template void RunPass() { T pass(ir_); } + IR *ir_ {nullptr}; +}; +struct IR final { + template void RunPass() { pass_manager_.RunPass(); } + PassManager pass_manager_; +}; +struct ThePass : Pass { + explicit ThePass(IR *ir) : Pass(ir) {} + ThePass(const ThePass &) = delete; + template void Bar(void *inst, Func func = [](void *) {}); +}; + +void foo(IR *ir) { ir->RunPass(); }