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 <jakub@redhat.com> 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.
This commit is contained in:
parent
0ba3e5ff14
commit
179e01085b
3 changed files with 68 additions and 30 deletions
|
@ -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<tree> 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)
|
||||
|
|
10
gcc/testsuite/g++.dg/cpp0x/pr119123.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/pr119123.C
Normal file
|
@ -0,0 +1,10 @@
|
|||
// PR c++/119123
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-O2 -g" }
|
||||
|
||||
struct S {
|
||||
template <typename> void foo (int = [] {}) const;
|
||||
};
|
||||
struct T {
|
||||
static void bar (const S &);
|
||||
};
|
25
gcc/testsuite/g++.dg/cpp0x/pr98533.C
Normal file
25
gcc/testsuite/g++.dg/cpp0x/pr98533.C
Normal file
|
@ -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 <typename T> void RunPass() { T pass(ir_); }
|
||||
IR *ir_ {nullptr};
|
||||
};
|
||||
struct IR final {
|
||||
template <typename T> void RunPass() { pass_manager_.RunPass<T>(); }
|
||||
PassManager pass_manager_;
|
||||
};
|
||||
struct ThePass : Pass {
|
||||
explicit ThePass(IR *ir) : Pass(ir) {}
|
||||
ThePass(const ThePass &) = delete;
|
||||
template <typename Func = bool (*)(void *)> void Bar(void *inst, Func func = [](void *) {});
|
||||
};
|
||||
|
||||
void foo(IR *ir) { ir->RunPass<ThePass>(); }
|
Loading…
Add table
Reference in a new issue