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
This commit is contained in:
Jason Merrill 2017-08-29 17:38:21 -04:00 committed by Jason Merrill
parent 888a985425
commit 88b811bd29
10 changed files with 81 additions and 105 deletions

View File

@ -1,5 +1,21 @@
2017-08-29 Jason Merrill <jason@redhat.com>
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.

View File

@ -9007,6 +9007,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **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",

View File

@ -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)

View File

@ -3015,6 +3015,7 @@ write_expression (tree expr)
{
scope = TREE_OPERAND (expr, 0);
member = TREE_OPERAND (expr, 1);
gcc_assert (!BASELINK_P (member));
}
else
{

View File

@ -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

View File

@ -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()));

View File

@ -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;

View File

@ -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<i>(); // Line (1)
};
l(A{});
}
template<int i>
void make_crash() {}
};

View File

@ -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<i>(); // Line (1)
};
l(A{});
}
template<int i>
void make_crash() {}
};

View File

@ -11,7 +11,7 @@ struct A
template <typename T> 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<int> b;
@ -37,7 +37,7 @@ template <typename T> 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<int> e;