Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Wed, Jan 17, 2018 at 4:07 PM, Jakub Jelinekwrote: > On Wed, Jan 17, 2018 at 02:31:29PM -0500, Jason Merrill wrote: >> > First, thanks for your messages. Personally, at this late time for 8, I >> > vote for something like my most recent grokdeclarator fix and yours above >> > for 83824. Then, for 9, or even 8.2, the more encompassing change for all >> > those chainons. Please both of you let me know how shall we proceed, I >> > could certainly take care of the latter too from now on. Thanks again! >> >> Let's go ahead with your patch to grokdeclarator. In the parser, >> let's do what Jakub is suggesting here: >> >> > So, either we want to go with what Paolo posted even in this case, >> > i.e. turn decl_specs->attributes into error_mark_node if attrs >> > is error_mark_node, and don't chainon anything to it if >> > decl_specs->attributes >> > is already error_mark_node, e.g. something like: >> > if (attrs == error_mark_node || decl_specs->attributes == error_mark_node) >> > decl_specs->attributes = error_mark_node; >> > else >> > decl_specs->attributes = chainon (decl_specs->attributes, attrs); >> >> without any assert. Putting this logic in an attr_chainon function sounds >> good. > > So like this? So far just tested with make check-c++-all on both > x86_64-linux and i686-linux, full bootstrap/regtest scheduled, ok if it > passes? I gave up on the original idea to return void and have the first > argument pointer, because while many of the calls do x = chainon (x, y);, > there are several ones that assign it to something else, like y = chainon (x, > y); > etc. Looks good. Jason
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Wed, Jan 17, 2018 at 02:31:29PM -0500, Jason Merrill wrote: > > First, thanks for your messages. Personally, at this late time for 8, I > > vote for something like my most recent grokdeclarator fix and yours above > > for 83824. Then, for 9, or even 8.2, the more encompassing change for all > > those chainons. Please both of you let me know how shall we proceed, I > > could certainly take care of the latter too from now on. Thanks again! > > Let's go ahead with your patch to grokdeclarator. In the parser, > let's do what Jakub is suggesting here: > > > So, either we want to go with what Paolo posted even in this case, > > i.e. turn decl_specs->attributes into error_mark_node if attrs > > is error_mark_node, and don't chainon anything to it if > > decl_specs->attributes > > is already error_mark_node, e.g. something like: > > if (attrs == error_mark_node || decl_specs->attributes == error_mark_node) > > decl_specs->attributes = error_mark_node; > > else > > decl_specs->attributes = chainon (decl_specs->attributes, attrs); > > without any assert. Putting this logic in an attr_chainon function sounds > good. So like this? So far just tested with make check-c++-all on both x86_64-linux and i686-linux, full bootstrap/regtest scheduled, ok if it passes? I gave up on the original idea to return void and have the first argument pointer, because while many of the calls do x = chainon (x, y);, there are several ones that assign it to something else, like y = chainon (x, y); etc. 2018-01-17 Jakub JelinekPR c++/83824 * parser.c (attr_chainon): New function. (cp_parser_label_for_labeled_statement, cp_parser_decl_specifier_seq, cp_parser_namespace_definition, cp_parser_init_declarator, cp_parser_type_specifier_seq, cp_parser_parameter_declaration, cp_parser_gnu_attributes_opt): Use it. (cp_parser_member_declaration, cp_parser_objc_class_ivars, cp_parser_objc_struct_declaration): Likewise. Don't reset prefix_attributes if attributes is error_mark_node. * g++.dg/cpp0x/pr83824.C: New test. --- gcc/cp/parser.c.jj 2018-01-13 17:57:38.115836072 +0100 +++ gcc/cp/parser.c 2018-01-17 20:46:21.809738257 +0100 @@ -10908,6 +10908,18 @@ cp_parser_statement (cp_parser* parser, "attributes at the beginning of statement are ignored"); } +/* Append ATTR to attribute list ATTRS. */ + +static tree +attr_chainon (tree attrs, tree attr) +{ + if (attrs == error_mark_node) +return error_mark_node; + if (attr == error_mark_node) +return error_mark_node; + return chainon (attrs, attr); +} + /* Parse the label for a labeled-statement, i.e. identifier : @@ -11027,7 +11039,7 @@ cp_parser_label_for_labeled_statement (c else if (!cp_parser_parse_definitely (parser)) ; else - attributes = chainon (attributes, attrs); + attributes = attr_chainon (attributes, attrs); } if (attributes != NULL_TREE) @@ -13394,8 +13406,7 @@ cp_parser_decl_specifier_seq (cp_parser* else { decl_specs->std_attributes - = chainon (decl_specs->std_attributes, - attrs); + = attr_chainon (decl_specs->std_attributes, attrs); if (decl_specs->locations[ds_std_attribute] == 0) decl_specs->locations[ds_std_attribute] = token->location; } @@ -13403,9 +13414,8 @@ cp_parser_decl_specifier_seq (cp_parser* } } - decl_specs->attributes - = chainon (decl_specs->attributes, -attrs); + decl_specs->attributes + = attr_chainon (decl_specs->attributes, attrs); if (decl_specs->locations[ds_attribute] == 0) decl_specs->locations[ds_attribute] = token->location; continue; @@ -18471,7 +18481,7 @@ cp_parser_namespace_definition (cp_parse identifier = cp_parser_identifier (parser); /* Parse any attributes specified after the identifier. */ - attribs = chainon (attribs, cp_parser_attributes_opt (parser)); + attribs = attr_chainon (attribs, cp_parser_attributes_opt (parser)); } if (cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE)) @@ -19633,7 +19643,7 @@ cp_parser_init_declarator (cp_parser* pa decl = grokfield (declarator, decl_specifiers, initializer, !is_non_constant_init, /*asmspec=*/NULL_TREE, - chainon (attributes, prefix_attributes)); + attr_chainon (attributes, prefix_attributes)); if (decl && TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); cp_finalize_omp_declare_simd (parser, decl); @@ -21007,9 +21017,9 @@ cp_parser_type_specifier_seq (cp_parser*
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Sat, Jan 13, 2018 at 7:59 AM, Paolo Carliniwrote: > Hi Jakub, all, > >> On 13 Jan 2018, at 12:32, Jakub Jelinek wrote: >> >>> On Sat, Jan 13, 2018 at 12:12:02PM +0100, Jakub Jelinek wrote: >>> Or we could not add those error_mark_nodes and >>> gcc_assert (seen_error () || cp_parser_error_occurred (parser)); >> >> This fixes the testcase: >> --- gcc/cp/parser.c.jj2018-01-11 18:58:48.386391801 +0100 >> +++ gcc/cp/parser.c2018-01-13 12:17:20.545347195 +0100 >> @@ -13403,6 +13403,9 @@ cp_parser_decl_specifier_seq (cp_parser* >>} >>} >> >> + if (attrs == error_mark_node) >> +gcc_assert (seen_error () || cp_parser_error_occurred (parser)); >> + else >>decl_specs->attributes >> = chainon (decl_specs->attributes, >> attrs); >> but there are 13 chainon calls like this in parser.c. Shouldn't we introduce >> a helper function for this, perhaps: >> >> void >> attr_chainon (cp_parser *parser, tree *attrs, tree attr) >> { >> /* Don't add error_mark_node to the chain, it can't be chained. >> Assert this is during error recovery. */ >> if (attr == error_mark_node) >>gcc_assert (seen_error () || cp_parser_error_occurred (parser)); >> else >>*attrs = chainon (*attrs, attr); >> } >> >> and change all affected spots, like >> >> attr_chainon (parser, _specs->attributes, attrs); >> >> ? > > First, thanks for your messages. Personally, at this late time for 8, I vote > for something like my most recent grokdeclarator fix and yours above for > 83824. Then, for 9, or even 8.2, the more encompassing change for all those > chainons. Please both of you let me know how shall we proceed, I could > certainly take care of the latter too from now on. Thanks again! Let's go ahead with your patch to grokdeclarator. In the parser, let's do what Jakub is suggesting here: > So, either we want to go with what Paolo posted even in this case, > i.e. turn decl_specs->attributes into error_mark_node if attrs > is error_mark_node, and don't chainon anything to it if decl_specs->attributes > is already error_mark_node, e.g. something like: > if (attrs == error_mark_node || decl_specs->attributes == error_mark_node) > decl_specs->attributes = error_mark_node; > else > decl_specs->attributes = chainon (decl_specs->attributes, attrs); without any assert. Putting this logic in an attr_chainon function sounds good. Jason
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi Jakub, all, > On 13 Jan 2018, at 12:32, Jakub Jelinekwrote: > >> On Sat, Jan 13, 2018 at 12:12:02PM +0100, Jakub Jelinek wrote: >> Or we could not add those error_mark_nodes and >> gcc_assert (seen_error () || cp_parser_error_occurred (parser)); > > This fixes the testcase: > --- gcc/cp/parser.c.jj2018-01-11 18:58:48.386391801 +0100 > +++ gcc/cp/parser.c2018-01-13 12:17:20.545347195 +0100 > @@ -13403,6 +13403,9 @@ cp_parser_decl_specifier_seq (cp_parser* >} >} > > + if (attrs == error_mark_node) > +gcc_assert (seen_error () || cp_parser_error_occurred (parser)); > + else >decl_specs->attributes > = chainon (decl_specs->attributes, > attrs); > but there are 13 chainon calls like this in parser.c. Shouldn't we introduce > a helper function for this, perhaps: > > void > attr_chainon (cp_parser *parser, tree *attrs, tree attr) > { > /* Don't add error_mark_node to the chain, it can't be chained. > Assert this is during error recovery. */ > if (attr == error_mark_node) >gcc_assert (seen_error () || cp_parser_error_occurred (parser)); > else >*attrs = chainon (*attrs, attr); > } > > and change all affected spots, like > > attr_chainon (parser, _specs->attributes, attrs); > > ? First, thanks for your messages. Personally, at this late time for 8, I vote for something like my most recent grokdeclarator fix and yours above for 83824. Then, for 9, or even 8.2, the more encompassing change for all those chainons. Please both of you let me know how shall we proceed, I could certainly take care of the latter too from now on. Thanks again! Paolo
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Sat, Jan 13, 2018 at 12:12:02PM +0100, Jakub Jelinek wrote: > Or we could not add those error_mark_nodes and > gcc_assert (seen_error () || cp_parser_error_occurred (parser)); This fixes the testcase: --- gcc/cp/parser.c.jj 2018-01-11 18:58:48.386391801 +0100 +++ gcc/cp/parser.c 2018-01-13 12:17:20.545347195 +0100 @@ -13403,6 +13403,9 @@ cp_parser_decl_specifier_seq (cp_parser* } } + if (attrs == error_mark_node) + gcc_assert (seen_error () || cp_parser_error_occurred (parser)); + else decl_specs->attributes = chainon (decl_specs->attributes, attrs); but there are 13 chainon calls like this in parser.c. Shouldn't we introduce a helper function for this, perhaps: void attr_chainon (cp_parser *parser, tree *attrs, tree attr) { /* Don't add error_mark_node to the chain, it can't be chained. Assert this is during error recovery. */ if (attr == error_mark_node) gcc_assert (seen_error () || cp_parser_error_occurred (parser)); else *attrs = chainon (*attrs, attr); } and change all affected spots, like attr_chainon (parser, _specs->attributes, attrs); ? Jakub
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Sat, Jan 13, 2018 at 12:10:22PM +0100, Jakub Jelinek wrote: > On Fri, Jan 12, 2018 at 01:13:17PM -0500, Jason Merrill wrote: > > On Thu, Jan 11, 2018 at 5:11 PM, Paolo Carlini> > wrote: > > > On 11/01/2018 21:33, Jason Merrill wrote: > > >> On 01/10/2018 06:50 PM, Paolo Carlini wrote: > > >>> > > >>> thus the below is a rather "dull" solution at the level of > > >>> cplus_decl_attributes itself: cp_check_const_attributes is tweaked to > > >>> check > > >>> for error_mark_node at each outer iteration > > >> > > >> This shouldn't be necessary; we should have returned error_mark_node for > > >> the attribute list rather than append it to something else, in which case > > >> the existing check for attributes == error_mark_node would have done the > > >> job. > > > > > > Indeed. That seems the most straightforward way to approach the issue. > > > Thanks. > > > > > > In grokdeclarator we could either explicitly assign error_mark_node to > > > *attrlist (instead of chaining) or simply drop the erroneous > > > declarator->std_attributes. Both solutions appear to work fine in > > > practice, > > > pass testing. > > > > Hmm, I think dropping the attributes is reasonable for grokdeclarator > > to do as error-recovery, similarly to how it discards an ill-formed > > exception-specification. But let's assert seen_error() in that case. > > PR83824 is simiar to this PR, just in a different spot, but again: > 13406 decl_specs->attributes > 13407 = chainon (decl_specs->attributes, > 13408 attrs); > in parser.c and decl_specs->attributes is error_mark_node and attrs > is error_mark_node too, yet seen_error () is false. The reason for that > is that we are doing tentative parsing here, so e.g. > if (!parens.require_close (parser)) > return error_mark_node; > doesn't report any error but just returns error_mark_node. > So, either we want to go with what Paolo posted even in this case, > i.e. turn decl_specs->attributes into error_mark_node if attrs > is error_mark_node, and don't chainon anything to it if decl_specs->attributes > is already error_mark_node, e.g. something like: > if (attrs == error_mark_node || decl_specs->attributes == error_mark_node) > decl_specs->attributes = error_mark_node; > else > decl_specs->attributes = chainon (decl_specs->attributes, attrs); > or we can not add error_mark_node attributes at all, but we can't assert > seen_error () in that case; perhaps track in a side boolean in decl_specs > whether attributes is errorneous. Or we could not add those error_mark_nodes and gcc_assert (seen_error () || cp_parser_error_occurred (parser)); Jakub
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Fri, Jan 12, 2018 at 01:13:17PM -0500, Jason Merrill wrote: > On Thu, Jan 11, 2018 at 5:11 PM, Paolo Carlini> wrote: > > On 11/01/2018 21:33, Jason Merrill wrote: > >> On 01/10/2018 06:50 PM, Paolo Carlini wrote: > >>> > >>> thus the below is a rather "dull" solution at the level of > >>> cplus_decl_attributes itself: cp_check_const_attributes is tweaked to > >>> check > >>> for error_mark_node at each outer iteration > >> > >> This shouldn't be necessary; we should have returned error_mark_node for > >> the attribute list rather than append it to something else, in which case > >> the existing check for attributes == error_mark_node would have done the > >> job. > > > > Indeed. That seems the most straightforward way to approach the issue. > > Thanks. > > > > In grokdeclarator we could either explicitly assign error_mark_node to > > *attrlist (instead of chaining) or simply drop the erroneous > > declarator->std_attributes. Both solutions appear to work fine in practice, > > pass testing. > > Hmm, I think dropping the attributes is reasonable for grokdeclarator > to do as error-recovery, similarly to how it discards an ill-formed > exception-specification. But let's assert seen_error() in that case. PR83824 is simiar to this PR, just in a different spot, but again: 13406 decl_specs->attributes 13407 = chainon (decl_specs->attributes, 13408attrs); in parser.c and decl_specs->attributes is error_mark_node and attrs is error_mark_node too, yet seen_error () is false. The reason for that is that we are doing tentative parsing here, so e.g. if (!parens.require_close (parser)) return error_mark_node; doesn't report any error but just returns error_mark_node. So, either we want to go with what Paolo posted even in this case, i.e. turn decl_specs->attributes into error_mark_node if attrs is error_mark_node, and don't chainon anything to it if decl_specs->attributes is already error_mark_node, e.g. something like: if (attrs == error_mark_node || decl_specs->attributes == error_mark_node) decl_specs->attributes = error_mark_node; else decl_specs->attributes = chainon (decl_specs->attributes, attrs); or we can not add error_mark_node attributes at all, but we can't assert seen_error () in that case; perhaps track in a side boolean in decl_specs whether attributes is errorneous. Jakub
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi, On 12/01/2018 19:13, Jason Merrill wrote: Hmm, I think dropping the attributes is reasonable for grokdeclarator to do as error-recovery, similarly to how it discards an ill-formed exception-specification. But let's assert seen_error() in that case. Agreed. The below passes testing. Thanks! Paolo. /// Index: cp/decl.c === --- cp/decl.c (revision 256592) +++ cp/decl.c (working copy) @@ -11487,9 +11487,15 @@ grokdeclarator (const cp_declarator *declarator, && declarator->kind == cdk_id && declarator->std_attributes && attrlist != NULL) -/* [dcl.meaning]/1: The optional attribute-specifier-seq following - a declarator-id appertains to the entity that is declared. */ -*attrlist = chainon (*attrlist, declarator->std_attributes); +{ + /* [dcl.meaning]/1: The optional attribute-specifier-seq following +a declarator-id appertains to the entity that is declared. */ + if (declarator->std_attributes != error_mark_node) + *attrlist = chainon (*attrlist, declarator->std_attributes); + else + /* We should have already diagnosed the issue (c++/78344). */ + gcc_assert (seen_error ()); +} /* Handle parameter packs. */ if (parameter_pack_p) Index: testsuite/g++.dg/cpp0x/alignas13.C === --- testsuite/g++.dg/cpp0x/alignas13.C (nonexistent) +++ testsuite/g++.dg/cpp0x/alignas13.C (working copy) @@ -0,0 +1,5 @@ +// PR c++/78344 +// { dg-do compile { target c++11 } } + +alignas(double) int f alignas; // { dg-error "30:expected '\\('" } +alignas(double) int g alignas(double; // { dg-error "37:expected '\\)'" }
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Thu, Jan 11, 2018 at 5:11 PM, Paolo Carliniwrote: > On 11/01/2018 21:33, Jason Merrill wrote: >> On 01/10/2018 06:50 PM, Paolo Carlini wrote: >>> >>> thus the below is a rather "dull" solution at the level of >>> cplus_decl_attributes itself: cp_check_const_attributes is tweaked to check >>> for error_mark_node at each outer iteration >> >> This shouldn't be necessary; we should have returned error_mark_node for >> the attribute list rather than append it to something else, in which case >> the existing check for attributes == error_mark_node would have done the >> job. > > Indeed. That seems the most straightforward way to approach the issue. > Thanks. > > In grokdeclarator we could either explicitly assign error_mark_node to > *attrlist (instead of chaining) or simply drop the erroneous > declarator->std_attributes. Both solutions appear to work fine in practice, > pass testing. Hmm, I think dropping the attributes is reasonable for grokdeclarator to do as error-recovery, similarly to how it discards an ill-formed exception-specification. But let's assert seen_error() in that case. Jason
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi, On 11/01/2018 21:33, Jason Merrill wrote: On 01/10/2018 06:50 PM, Paolo Carlini wrote: thus the below is a rather "dull" solution at the level of cplus_decl_attributes itself: cp_check_const_attributes is tweaked to check for error_mark_node at each outer iteration This shouldn't be necessary; we should have returned error_mark_node for the attribute list rather than append it to something else, in which case the existing check for attributes == error_mark_node would have done the job. Indeed. That seems the most straightforward way to approach the issue. Thanks. In grokdeclarator we could either explicitly assign error_mark_node to *attrlist (instead of chaining) or simply drop the erroneous declarator->std_attributes. Both solutions appear to work fine in practice, pass testing. Paolo. / Index: cp/decl.c === --- cp/decl.c (revision 256556) +++ cp/decl.c (working copy) @@ -11487,9 +11487,15 @@ grokdeclarator (const cp_declarator *declarator, && declarator->kind == cdk_id && declarator->std_attributes && attrlist != NULL) -/* [dcl.meaning]/1: The optional attribute-specifier-seq following - a declarator-id appertains to the entity that is declared. */ -*attrlist = chainon (*attrlist, declarator->std_attributes); +{ + /* [dcl.meaning]/1: The optional attribute-specifier-seq following +a declarator-id appertains to the entity that is declared. */ + if (declarator->std_attributes != error_mark_node) + *attrlist = chainon (*attrlist, declarator->std_attributes); + else + /* We should have already diagnosed the issue (c++/78344). */ + *attrlist = error_mark_node; +} /* Handle parameter packs. */ if (parameter_pack_p) Index: testsuite/g++.dg/cpp0x/alignas13.C === --- testsuite/g++.dg/cpp0x/alignas13.C (nonexistent) +++ testsuite/g++.dg/cpp0x/alignas13.C (working copy) @@ -0,0 +1,5 @@ +// PR c++/78344 +// { dg-do compile { target c++11 } } + +alignas(double) int f alignas; // { dg-error "30:expected '\\('" } +alignas(double) int g alignas(double; // { dg-error "37:expected '\\)'" } Index: cp/decl.c === --- cp/decl.c (revision 256556) +++ cp/decl.c (working copy) @@ -11486,6 +11486,8 @@ grokdeclarator (const cp_declarator *declarator, if (declarator && declarator->kind == cdk_id && declarator->std_attributes + /* We should have already diagnosed the issue (c++/78344). */ + && declarator->std_attributes != error_mark_node && attrlist != NULL) /* [dcl.meaning]/1: The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared. */ Index: testsuite/g++.dg/cpp0x/alignas13.C === --- testsuite/g++.dg/cpp0x/alignas13.C (nonexistent) +++ testsuite/g++.dg/cpp0x/alignas13.C (working copy) @@ -0,0 +1,5 @@ +// PR c++/78344 +// { dg-do compile { target c++11 } } + +alignas(double) int f alignas; // { dg-error "30:expected '\\('" } +alignas(double) int g alignas(double; // { dg-error "37:expected '\\)'" }
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On 01/10/2018 06:50 PM, Paolo Carlini wrote: thus the below is a rather "dull" solution at the level of cplus_decl_attributes itself: cp_check_const_attributes is tweaked to check for error_mark_node at each outer iteration This shouldn't be necessary; we should have returned error_mark_node for the attribute list rather than append it to something else, in which case the existing check for attributes == error_mark_node would have done the job. Jason
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
... today I played a bit with the other idea inspired by your feedback. Irrespective of the special issue at hand, it seems in principle interesting to me that when we are sure that we aren't parsing tentatively anymore we can do something more radical for the sake of better error recovery. Anyway, the below passes testing and yes, there are cases in our testsuite where cp_parser_std_attribute_spec returns error_mark_node and cp_parser_uncommitted_to_tentative_parse_p is true. Paolo. /// Index: cp/parser.c === --- cp/parser.c (revision 256543) +++ cp/parser.c (working copy) @@ -25382,7 +25382,15 @@ cp_parser_std_attribute_spec_seq (cp_parser *parse if (attr_spec == NULL_TREE) break; if (attr_spec == error_mark_node) - return error_mark_node; + { + if (!cp_parser_uncommitted_to_tentative_parse_p (parser)) + /* When guaranteed to be correct, behaving as if the + erroneous attributes weren't there in the first place + makes for very good error recovery (c++/78344). */ + return NULL_TREE; + else + return error_mark_node; + } if (attr_last) TREE_CHAIN (attr_last) = attr_spec; Index: testsuite/g++.dg/cpp0x/alignas13.C === --- testsuite/g++.dg/cpp0x/alignas13.C (nonexistent) +++ testsuite/g++.dg/cpp0x/alignas13.C (working copy) @@ -0,0 +1,5 @@ +// PR c++/78344 +// { dg-do compile { target c++11 } } + +alignas(double) int f alignas; // { dg-error "30:expected '\\('" } +alignas(double) int g alignas(double; // { dg-error "37:expected '\\)'" }
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi again, thus the below is a rather "dull" solution at the level of cplus_decl_attributes itself: cp_check_const_attributes is tweaked to check for error_mark_node at each outer iteration and consistently return a bool, which is then checked by the caller in order to possibly bail out (this is similar to the check_for_bare_parameter_packs call a few lines before). Testing is Ok on x86_64-linux. Thanks, Paolo. /cp 2018-01-11 Paolo CarliniPR c++/78344 * decl2.c (cp_check_const_attributes): Check for error_mark_node at each outer iterations; return a bool. (cplus_decl_attributes): Adjust cp_check_const_attributes call. /testsuite 2018-01-10 Paolo Carlini PR c++/78344 * g++.dg/cpp0x/alignas13.C: New. Index: cp/decl2.c === --- cp/decl2.c (revision 256451) +++ cp/decl2.c (working copy) @@ -1396,19 +1396,17 @@ cp_reconstruct_complex_type (tree type, tree botto } /* Replaces any constexpr expression that may be into the attributes - arguments with their reduced value. */ + arguments with their reduced value. Returns FALSE if encounters + error_mark_node, TRUE otherwise. */ -static void +static bool cp_check_const_attributes (tree attributes) { - if (attributes == error_mark_node) -return; - - tree attr; - for (attr = attributes; attr; attr = TREE_CHAIN (attr)) + for (tree attr = attributes; attr; attr = TREE_CHAIN (attr)) { - tree arg; - for (arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg)) + if (attr == error_mark_node) + return false; + for (tree arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg)) { tree expr = TREE_VALUE (arg); if (EXPR_P (expr)) @@ -1415,6 +1413,7 @@ cp_check_const_attributes (tree attributes) TREE_VALUE (arg) = maybe_constant_value (expr); } } + return true; } /* Return true if TYPE is an OpenMP mappable type. */ @@ -1528,7 +1527,8 @@ cplus_decl_attributes (tree *decl, tree attributes save_template_attributes (, decl, flags); } - cp_check_const_attributes (attributes); + if (!cp_check_const_attributes (attributes)) +return; if (TREE_CODE (*decl) == TEMPLATE_DECL) decl = _TEMPLATE_RESULT (*decl); Index: testsuite/g++.dg/cpp0x/alignas13.C === --- testsuite/g++.dg/cpp0x/alignas13.C (nonexistent) +++ testsuite/g++.dg/cpp0x/alignas13.C (working copy) @@ -0,0 +1,5 @@ +// PR c++/78344 +// { dg-do compile { target c++11 } } + +alignas(double) int f alignas; // { dg-error "30:expected '\\('" } +alignas(double) int g alignas(double; // { dg-error "37:expected '\\)'" }
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi, On 10/01/2018 17:58, Jason Merrill wrote: On Wed, Jan 10, 2018 at 11:33 AM, Paolo Carliniwrote: Hi, On 10/01/2018 16:32, Jason Merrill wrote: On Fri, Dec 22, 2017 at 7:34 PM, Paolo Carlini wrote: in this error recovery issue cp_check_const_attributes and more generally cplus_decl_attributes have lots of troubles handling the error_mark_node returned by cp_parser_std_attribute_spec_seq, as called by cp_parser_direct_declarator. I fiddled quite a bit with these parsing facilities to eventually notice that boldly changing cp_parser_std_attribute_spec_seq to return NULL_TREE instead of error_mark_node when cp_parser_std_attribute_spec returns error_mark_node in the loop cures the bug at issue as a special case. Hmm, I'm skeptical. In general, we want to use error_mark_node to distinguish between something not being there and being there but wrong. I see what you mean. But consider that we already emitted diagnostic anyway, I'm not sure we can rely on that; cp_parser_error doesn't emit anything when parsing tentatively. Ok. I'm going to investigate that a bit more - the obvious idea would be limiting somehow the approach to when we are *not* parsing tentatively - otherwise I'll see if we can handle elegantly enough those error_mark_nodes. I committed the other straightforward change which you approved, thanks about that. Paolo.
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Wed, Jan 10, 2018 at 11:33 AM, Paolo Carliniwrote: > Hi, > > On 10/01/2018 16:32, Jason Merrill wrote: >> >> On Fri, Dec 22, 2017 at 7:34 PM, Paolo Carlini >> wrote: >>> >>> in this error recovery issue cp_check_const_attributes and more generally >>> cplus_decl_attributes have lots of troubles handling the error_mark_node >>> returned by cp_parser_std_attribute_spec_seq, as called by >>> cp_parser_direct_declarator. I fiddled quite a bit with these parsing >>> facilities to eventually notice that boldly changing >>> cp_parser_std_attribute_spec_seq to return NULL_TREE instead of >>> error_mark_node when cp_parser_std_attribute_spec returns error_mark_node >>> in >>> the loop cures the bug at issue as a special case. >> >> Hmm, I'm skeptical. In general, we want to use error_mark_node to >> distinguish between something not being there and being there but >> wrong. > > I see what you mean. But consider that we already emitted diagnostic anyway, I'm not sure we can rely on that; cp_parser_error doesn't emit anything when parsing tentatively. > and, important detail, isn't that we are dropping some correct attributes, > we are dropping all of them anyway with error_mark_node or NULL_TREE the > same way. It's just that with NULL_TREE we are behaving during error > recovery as if the attributes weren't there in the first place. I'm not sure > if this was 100% clear... Would you like to have some additional details? It's clear, I'm just not convinced it's what we want. Jason
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi, On 10/01/2018 16:32, Jason Merrill wrote: On Fri, Dec 22, 2017 at 7:34 PM, Paolo Carliniwrote: in this error recovery issue cp_check_const_attributes and more generally cplus_decl_attributes have lots of troubles handling the error_mark_node returned by cp_parser_std_attribute_spec_seq, as called by cp_parser_direct_declarator. I fiddled quite a bit with these parsing facilities to eventually notice that boldly changing cp_parser_std_attribute_spec_seq to return NULL_TREE instead of error_mark_node when cp_parser_std_attribute_spec returns error_mark_node in the loop cures the bug at issue as a special case. Hmm, I'm skeptical. In general, we want to use error_mark_node to distinguish between something not being there and being there but wrong. I see what you mean. But consider that we already emitted diagnostic anyway, and, important detail, isn't that we are dropping some correct attributes, we are dropping all of them anyway with error_mark_node or NULL_TREE the same way. It's just that with NULL_TREE we are behaving during error recovery as if the attributes weren't there in the first place. I'm not sure if this was 100% clear... Would you like to have some additional details? Thanks! Paolo.
Re: [C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
On Fri, Dec 22, 2017 at 7:34 PM, Paolo Carliniwrote: > in this error recovery issue cp_check_const_attributes and more generally > cplus_decl_attributes have lots of troubles handling the error_mark_node > returned by cp_parser_std_attribute_spec_seq, as called by > cp_parser_direct_declarator. I fiddled quite a bit with these parsing > facilities to eventually notice that boldly changing > cp_parser_std_attribute_spec_seq to return NULL_TREE instead of > error_mark_node when cp_parser_std_attribute_spec returns error_mark_node in > the loop cures the bug at issue as a special case. Hmm, I'm skeptical. In general, we want to use error_mark_node to distinguish between something not being there and being there but wrong. > I also noticed that in cp_parser_std_attribute_spec we are using > token_pair::require_open / require_close very peculiarly, issuing a > cp_parser_error when the returned bool is false instead of simply bailing > out with error_mark_node and that in fact causes duplicate diagnostics about > expected '(' / ')', respectively. The hunks for this issue are OK. Jason
[C++ Patch] PR 78344 ("ICE on invalid c++ code (tree check: expected tree_list, have error_mark in cp_check_const_attributes, at cp/decl2.c:1347")
Hi, in this error recovery issue cp_check_const_attributes and more generally cplus_decl_attributes have lots of troubles handling the error_mark_node returned by cp_parser_std_attribute_spec_seq, as called by cp_parser_direct_declarator. I fiddled quite a bit with these parsing facilities to eventually notice that boldly changing cp_parser_std_attribute_spec_seq to return NULL_TREE instead of error_mark_node when cp_parser_std_attribute_spec returns error_mark_node in the loop cures the bug at issue as a special case. I also noticed that in cp_parser_std_attribute_spec we are using token_pair::require_open / require_close very peculiarly, issuing a cp_parser_error when the returned bool is false instead of simply bailing out with error_mark_node and that in fact causes duplicate diagnostics about expected '(' / ')', respectively. Tested x86_64-linux. Thanks, Paolo. /// /cp 2017-12-22 Paolo CarliniPR c++/78344 * parser.c (cp_parser_std_attribute_spec_seq): When cp_parser_std_attribute_spec returns error_mark_node return back NULL_TREE instead of error_mark_node. * parser.c (cp_parser_std_attribute_spec): When token_pair::require_open / require_close returns false simply return error_mark_node, do not issue a duplicate cp_parser_error about expected '(' / ')', respectively. /testsuite 2017-12-22 Paolo Carlini PR c++/78344 * g++.dg/cpp0x/alignas13.C: New. Index: cp/parser.c === --- cp/parser.c (revision 255983) +++ cp/parser.c (working copy) @@ -25300,10 +25300,7 @@ cp_parser_std_attribute_spec (cp_parser *parser) matching_parens parens; if (!parens.require_open (parser)) - { - cp_parser_error (parser, "expected %<(%>"); - return error_mark_node; - } + return error_mark_node; cp_parser_parse_tentatively (parser); alignas_expr = cp_parser_type_id (parser); @@ -25333,10 +25330,7 @@ cp_parser_std_attribute_spec (cp_parser *parser) return error_mark_node; if (!parens.require_close (parser)) - { - cp_parser_error (parser, "expected %<)%>"); - return error_mark_node; - } + return error_mark_node; /* Build the C++-11 representation of an 'aligned' attribute. */ @@ -25367,7 +25361,7 @@ cp_parser_std_attribute_spec_seq (cp_parser *parse if (attr_spec == NULL_TREE) break; if (attr_spec == error_mark_node) - return error_mark_node; + return NULL_TREE; if (attr_last) TREE_CHAIN (attr_last) = attr_spec; Index: testsuite/g++.dg/cpp0x/alignas13.C === --- testsuite/g++.dg/cpp0x/alignas13.C (nonexistent) +++ testsuite/g++.dg/cpp0x/alignas13.C (working copy) @@ -0,0 +1,5 @@ +// PR c++/78344 +// { dg-do compile { target c++11 } } + +alignas(double) int f alignas; // { dg-error "30:expected '\\('" } +alignas(double) int g alignas(double; // { dg-error "37:expected '\\)'" }