commit 28df39b2192b5feeffa6dd2b8208cf0270ac5330 Author: Jason Merrill Date: Thu Aug 24 14:09:01 2017 -0400 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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f7f9297..c446057 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 4747a72..9ba3df1 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 a87f97f..ce7c0c5 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 d0d71fa..47d91bf 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 8f28221..b2e58d2 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 dbac7f3..aab92d5 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 0000000..52d25af --- /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 0000000..d321a07 --- /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 8f1f6a7..21a68aa 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;