From 88b811bd29063036fd4536ee1312b1269cade6ed Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 29 Aug 2017 17:38:21 -0400 Subject: [PATCH] PR c++/81236 - ICE with template-id in generic lambda * semantics.c (finish_id_expression): Remove special dependent case. Avoid some later pieces when dependent. (finish_qualified_id_expr): Do normal BASELINK handling in a template. Always build a SCOPE_REF for a destructor BIT_NOT_EXPR. (parsing_default_capturing_generic_lambda_in_template): Remove. * parser.c (cp_parser_postfix_dot_deref_expression): Always give an error for types that will never be complete. * mangle.c (write_expression): Add sanity check. * tree.c (build_qualified_name): Add sanity check. (cp_walk_subtrees): Walk into the class context of a BASELINK. * lambda.c (add_capture): Improve diagnostic for generic lambda capture failure. * call.c (build_new_method_call_1): Print the right constructor name. From-SVN: r251438 --- gcc/cp/ChangeLog | 16 ++++ gcc/cp/call.c | 1 + gcc/cp/lambda.c | 6 +- gcc/cp/mangle.c | 1 + gcc/cp/parser.c | 30 +----- gcc/cp/semantics.c | 91 ++++--------------- gcc/cp/tree.c | 3 + .../g++.dg/cpp1y/lambda-generic-this1.C | 17 ++++ .../g++.dg/cpp1y/lambda-generic-this1a.C | 17 ++++ gcc/testsuite/g++.dg/template/pseudodtor3.C | 4 +- 10 files changed, 81 insertions(+), 105 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6e1db068ebf..8532f57e91a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,21 @@ 2017-08-29 Jason Merrill + PR c++/81236 - ICE with template-id in generic lambda + * semantics.c (finish_id_expression): Remove special dependent case. + Avoid some later pieces when dependent. + (finish_qualified_id_expr): Do normal BASELINK handling in a + template. Always build a SCOPE_REF for a destructor BIT_NOT_EXPR. + (parsing_default_capturing_generic_lambda_in_template): Remove. + * parser.c (cp_parser_postfix_dot_deref_expression): Always give an + error for types that will never be complete. + * mangle.c (write_expression): Add sanity check. + * tree.c (build_qualified_name): Add sanity check. + (cp_walk_subtrees): Walk into the class context of a BASELINK. + * lambda.c (add_capture): Improve diagnostic for generic lambda + capture failure. + * call.c (build_new_method_call_1): Print the right constructor + name. + Reimplement handling of lambdas in templates. * cp-tree.h (LAMBDA_FUNCTION_P): Check DECL_DECLARES_FUNCTION_P. * decl.c (start_preparsed_function): Call start_lambda_scope. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f7f92978052..c446057cfba 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9007,6 +9007,7 @@ build_new_method_call_1 (tree instance, tree fns, vec **args, if (! (complain & tf_error)) return error_mark_node; + basetype = DECL_CONTEXT (fn); name = constructor_name (basetype); if (permerror (input_location, "cannot call constructor %<%T::%D%> directly", diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 4747a727173..9ba3df10363 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -590,7 +590,11 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, /* Add it to the appropriate closure class if we've started it. */ if (current_class_type && current_class_type == LAMBDA_EXPR_CLOSURE (lambda)) - finish_member_declaration (member); + { + if (COMPLETE_TYPE_P (current_class_type)) + internal_error ("trying to capture %qD after closure is complete", id); + finish_member_declaration (member); + } tree listmem = member; if (variadic) diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index a87f97fdf9f..ce7c0c51f0a 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3015,6 +3015,7 @@ write_expression (tree expr) { scope = TREE_OPERAND (expr, 0); member = TREE_OPERAND (expr, 1); + gcc_assert (!BASELINK_P (member)); } else { diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d0d71fa1dae..47d91bfa9a7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7446,11 +7446,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, /* In a template, be permissive by treating an object expression of incomplete type as dependent (after a pedwarn). */ diagnostic_t kind = (processing_template_decl + && MAYBE_CLASS_TYPE_P (scope) ? DK_PEDWARN : DK_ERROR); cxx_incomplete_type_diagnostic (location_of (postfix_expression), postfix_expression, scope, kind); + if (!MAYBE_CLASS_TYPE_P (scope)) + return error_mark_node; if (processing_template_decl) { dependent_p = true; @@ -20671,33 +20674,6 @@ parsing_nsdmi (void) return false; } -/* Return true iff our current scope is a default capturing generic lambda - defined within a template. FIXME: This is part of a workaround (see - semantics.c) to handle building lambda closure types correctly in templates - which we ultimately want to defer to instantiation time. */ - -bool -parsing_default_capturing_generic_lambda_in_template (void) -{ - if (!processing_template_decl || !current_class_type) - return false; - - tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type); - if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE) - return false; - - tree callop = lambda_function (lam); - if (!callop) - return false; - - return (DECL_TEMPLATE_INFO (callop) - && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop) - && ((current_nonlambda_class_type () - && CLASSTYPE_TEMPLATE_INFO (current_nonlambda_class_type ())) - || ((current_nonlambda_function () - && DECL_TEMPLATE_INFO (current_nonlambda_function ()))))); -} - /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8f2822107d6..b2e58d2dbf0 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2035,7 +2035,7 @@ finish_qualified_id_expr (tree qualifying_class, qualifying_class); pop_deferring_access_checks (); } - else if (BASELINK_P (expr) && !processing_template_decl) + else if (BASELINK_P (expr)) { /* See if any of the functions are non-static members. */ /* If so, the expression may be relative to 'this'. */ @@ -2055,8 +2055,6 @@ finish_qualified_id_expr (tree qualifying_class, expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false, complain); } - else if (BASELINK_P (expr)) - ; else { /* In a template, return a SCOPE_REF for most qualified-ids @@ -2065,7 +2063,8 @@ finish_qualified_id_expr (tree qualifying_class, know we have access and building up the SCOPE_REF confuses non-type template argument handling. */ if (processing_template_decl - && !currently_open_class (qualifying_class)) + && (!currently_open_class (qualifying_class) + || TREE_CODE (expr) == BIT_NOT_EXPR)) expr = build_qualified_name (TREE_TYPE (expr), qualifying_class, expr, template_p); @@ -3595,78 +3594,12 @@ finish_id_expression (tree id_expression, ? CP_ID_KIND_UNQUALIFIED_DEPENDENT : CP_ID_KIND_UNQUALIFIED))); - /* If the name was dependent on a template parameter and we're not in a - default capturing generic lambda within a template, we will resolve the - name at instantiation time. FIXME: For lambdas, we should defer - building the closure type until instantiation time then we won't need - the extra test here. */ if (dependent_p - && !parsing_default_capturing_generic_lambda_in_template ()) - { - if (DECL_P (decl) - && any_dependent_type_attributes_p (DECL_ATTRIBUTES (decl))) - /* Dependent type attributes on the decl mean that the TREE_TYPE is - wrong, so just return the identifier. */ - return id_expression; - - /* If we found a variable, then name lookup during the - instantiation will always resolve to the same VAR_DECL - (or an instantiation thereof). */ - if (VAR_P (decl) - || TREE_CODE (decl) == CONST_DECL - || TREE_CODE (decl) == PARM_DECL) - { - mark_used (decl); - return convert_from_reference (decl); - } - - /* Create a SCOPE_REF for qualified names, if the scope is - dependent. */ - if (scope) - { - if (TYPE_P (scope)) - { - if (address_p && done) - decl = finish_qualified_id_expr (scope, decl, - done, address_p, - template_p, - template_arg_p, - tf_warning_or_error); - else - { - tree type = NULL_TREE; - if (DECL_P (decl) && !dependent_scope_p (scope)) - type = TREE_TYPE (decl); - decl = build_qualified_name (type, - scope, - id_expression, - template_p); - } - } - if (TREE_TYPE (decl)) - decl = convert_from_reference (decl); - return decl; - } - /* A TEMPLATE_ID already contains all the information we - need. */ - if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR) - return id_expression; - /* The same is true for FIELD_DECL, but we also need to - make sure that the syntax is correct. */ - else if (TREE_CODE (decl) == FIELD_DECL) - { - /* Since SCOPE is NULL here, this is an unqualified name. - Access checking has been performed during name lookup - already. Turn off checking to avoid duplicate errors. */ - push_deferring_access_checks (dk_no_check); - decl = finish_non_static_data_member - (decl, NULL_TREE, - /*qualifying_scope=*/NULL_TREE); - pop_deferring_access_checks (); - return decl; - } - return id_expression; - } + && DECL_P (decl) + && any_dependent_type_attributes_p (DECL_ATTRIBUTES (decl))) + /* Dependent type attributes on the decl mean that the TREE_TYPE is + wrong, so just return the identifier. */ + return id_expression; if (TREE_CODE (decl) == NAMESPACE_DECL) { @@ -3700,6 +3633,7 @@ finish_id_expression (tree id_expression, expression. Template parameters have already been handled above. */ if (! error_operand_p (decl) + && !dependent_p && integral_constant_expression_p && ! decl_constant_var_p (decl) && TREE_CODE (decl) != CONST_DECL @@ -3726,6 +3660,7 @@ finish_id_expression (tree id_expression, decl = build_cxx_call (wrap, 0, NULL, tf_warning_or_error); } else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR + && !dependent_p && variable_template_p (TREE_OPERAND (decl, 0))) { decl = finish_template_variable (decl); @@ -3734,6 +3669,12 @@ finish_id_expression (tree id_expression, } else if (scope) { + if (TREE_CODE (decl) == SCOPE_REF) + { + gcc_assert (same_type_p (scope, TREE_OPERAND (decl, 0))); + decl = TREE_OPERAND (decl, 1); + } + decl = (adjust_result_of_qualified_name_lookup (decl, scope, current_nonlambda_class_type())); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index dbac7f3c550..aab92d5e9d5 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2028,6 +2028,7 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p) || scope == error_mark_node || name == error_mark_node) return error_mark_node; + gcc_assert (TREE_CODE (name) != SCOPE_REF); t = build2 (SCOPE_REF, type, scope, name); QUALIFIED_NAME_IS_TEMPLATE (t) = template_p; PTRMEM_OK_P (t) = true; @@ -4663,6 +4664,8 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, break; case BASELINK: + if (BASELINK_QUALIFIED_P (*tp)) + WALK_SUBTREE (BINFO_TYPE (BASELINK_ACCESS_BINFO (*tp))); WALK_SUBTREE (BASELINK_FUNCTIONS (*tp)); *walk_subtrees_p = 0; break; diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C new file mode 100644 index 00000000000..52d25af9c5a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C @@ -0,0 +1,17 @@ +// PR c++/81236 +// { dg-do compile { target c++14 } } + +struct A { constexpr operator int() { return 24; } }; + +struct MyType { + void crash() { + auto l = [&](auto i){ + make_crash(); // Line (1) + }; + + l(A{}); + } + + template + void make_crash() {} +}; diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C new file mode 100644 index 00000000000..d321a0773ee --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C @@ -0,0 +1,17 @@ +// PR c++/81236 +// { dg-do compile { target c++14 } } + +struct A { constexpr operator int() { return 24; } }; + +struct MyType { + void crash() { + auto l = [&](auto i){ + MyType::make_crash(); // Line (1) + }; + + l(A{}); + } + + template + void make_crash() {} +}; diff --git a/gcc/testsuite/g++.dg/template/pseudodtor3.C b/gcc/testsuite/g++.dg/template/pseudodtor3.C index 8f1f6a736a8..21a68aaac45 100644 --- a/gcc/testsuite/g++.dg/template/pseudodtor3.C +++ b/gcc/testsuite/g++.dg/template/pseudodtor3.C @@ -11,7 +11,7 @@ struct A template struct B { T &foo (); - B () { foo.~T (); } // { dg-error "15:invalid use of member" } + B () { foo.~T (); } // { dg-error "10:invalid use of member" } }; B b; @@ -37,7 +37,7 @@ template struct E { T &foo (); typedef long int U; - E () { foo.~U (); } // { dg-error "10:is not of type" } + E () { foo.~U (); } // { dg-error "10:invalid use of member" } }; E e;