mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-28 06:14:10 +08:00
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:
parent
888a985425
commit
88b811bd29
@ -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.
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -3015,6 +3015,7 @@ write_expression (tree expr)
|
||||
{
|
||||
scope = TREE_OPERAND (expr, 0);
|
||||
member = TREE_OPERAND (expr, 1);
|
||||
gcc_assert (!BASELINK_P (member));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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;
|
||||
|
17
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C
Normal file
17
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C
Normal 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() {}
|
||||
};
|
17
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C
Normal file
17
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C
Normal 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() {}
|
||||
};
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user