c++: non-constant non-dependent decltype folding [PR104823]
When processing a non-dependent decltype operand we want to instantiate it even if it's non-constant, since non-dependent decltype is always resolved ahead of time. But currently finish_decltype_type uses instantiate_non_dependent_expr, which instantiates only potentially constant expressions, and this causes us to miss diagnosing the narrowing conversion in S{id(v)} in the below testcase because we never instantiate this non-constant non-dependent decltype operand. In light of > On Mon, 7 Mar 2022, Jason Merrill wrote: >> On 3/7/22 14:41, Patrick Palka wrote: >>> instantiate_non_dependent_expr instantiates only potentially constant >>> expressions >> >> Hmm, that now strikes me as a problematic interface, as we don't know whether >> what we get back is template or non-template trees. this patch drops the potentially-constant check in i_n_d_e and turns its dependence check into a checking_assert, since most callers already check that the argument is non-dependent; thus i_n_d_e now instantiates even non-constant expressions and always returns non-templated trees. This patch also relaxes the dependence check in i_n_d_e to use the _uneval version (since that's what finish_decltype_type uses) and strengthens the dependence checks used by other callers accordingly. In cp_parser_parenthesized_expression_list_elt we were calling instantiate_non_dependent_expr (when parsing an attribute list) without first checking for non-dependence. We could fix this by guarding the call appropriately, but I noticed we also fold non-dependent attributes later from cp_check_const_attribute, so this earlier folding is at best redundant. And it currently causes us to reject constexpr-attribute4.C below due to the second folding seeing non-templated trees. Thus the right solution here seems to be to remove this unguarded call to i_n_d_e so that we end up instantiating non-dependent attributes only once. Finally, after calling i_n_d_e in finish_decltype_type we need to keep processing_template_decl cleared for sake of the later call to lvalue_kind, which handles templated and non-templated COND_EXPR differently. Otherwise we'd incorrectly reject the declaration of g in cpp0x/cond2.C with: error: 'g' declared as function returning a function PR c++/104823 gcc/cp/ChangeLog: * except.cc (build_noexcept_spec): Strengthen dependence check to instantiation_dependent_expression_p. * parser.cc (cp_parser_parenthesized_expression_list_elt): Remove fold_expr_p parameter, and don't call instantiate_non_dependent_expr. (cp_parser_parenthesized_expression_list): Adjust accordingly. * pt.cc (expand_integer_pack): Strengthen dependence check to instantiation_dependent_expression_p. (instantiate_non_dependent_expr_internal): Adjust comment. (instantiate_non_dependent_expr_sfinae): Likewise. Drop the potentially-constant check, and relax and turn the dependence check into a checking assert. (instantiate_non_dependent_or_null): Adjust comment. * semantics.cc (finish_decltype_type): Keep processing_template_decl cleared after calling instantiate_non_dependent_expr_sfinae. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/Wnarrowing19.C: New test.
This commit is contained in:
parent
e32869a17b
commit
ec0f53a3a5
6 changed files with 35 additions and 26 deletions
|
@ -1253,7 +1253,7 @@ build_noexcept_spec (tree expr, tsubst_flags_t complain)
|
|||
if (check_for_bare_parameter_packs (expr))
|
||||
return error_mark_node;
|
||||
if (TREE_CODE (expr) != DEFERRED_NOEXCEPT
|
||||
&& !value_dependent_expression_p (expr))
|
||||
&& !instantiation_dependent_expression_p (expr))
|
||||
{
|
||||
expr = build_converted_constant_bool_expr (expr, complain);
|
||||
expr = instantiate_non_dependent_expr_sfinae (expr, complain);
|
||||
|
|
|
@ -7958,7 +7958,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
|
|||
static cp_expr
|
||||
cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
|
||||
bool allow_expansion_p,
|
||||
bool fold_expr_p,
|
||||
bool *non_constant_p)
|
||||
{
|
||||
cp_expr expr (NULL_TREE);
|
||||
|
@ -7985,9 +7984,6 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
|
|||
else
|
||||
expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p);
|
||||
|
||||
if (fold_expr_p)
|
||||
expr = instantiate_non_dependent_expr (expr);
|
||||
|
||||
/* If we have an ellipsis, then this is an expression expansion. */
|
||||
if (allow_expansion_p
|
||||
&& cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
|
||||
|
@ -8053,8 +8049,6 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
|
|||
false,
|
||||
/*allow_exp_p=*/
|
||||
true,
|
||||
/*fold_expr_p=*/
|
||||
false,
|
||||
/*non_cst_p=*/
|
||||
NULL);
|
||||
|
||||
|
@ -8424,7 +8418,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
|
|||
bool wrap_locations_p)
|
||||
{
|
||||
vec<tree, va_gc> *expression_list;
|
||||
bool fold_expr_p = is_attribute_list != non_attr;
|
||||
tree identifier = NULL_TREE;
|
||||
bool saved_greater_than_is_operator_p;
|
||||
|
||||
|
@ -8467,7 +8460,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
|
|||
expr
|
||||
= cp_parser_parenthesized_expression_list_elt (parser, cast_p,
|
||||
allow_expansion_p,
|
||||
fold_expr_p,
|
||||
non_constant_p);
|
||||
|
||||
if (wrap_locations_p)
|
||||
|
|
25
gcc/cp/pt.cc
25
gcc/cp/pt.cc
|
@ -3817,7 +3817,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
|
|||
tree hi = tsubst_copy_and_build (ohi, args, complain, in_decl,
|
||||
false/*fn*/, true/*int_cst*/);
|
||||
|
||||
if (value_dependent_expression_p (hi))
|
||||
if (instantiation_dependent_expression_p (hi))
|
||||
{
|
||||
if (hi != ohi)
|
||||
{
|
||||
|
@ -6349,9 +6349,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
|
|||
|
||||
/* The actual substitution part of instantiate_non_dependent_expr_sfinae,
|
||||
to be used when the caller has already checked
|
||||
(processing_template_decl
|
||||
&& !instantiation_dependent_expression_p (expr)
|
||||
&& potential_constant_expression (expr))
|
||||
!instantiation_dependent_uneval_expression_p (expr)
|
||||
and cleared processing_template_decl. */
|
||||
|
||||
tree
|
||||
|
@ -6365,8 +6363,7 @@ instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
|
|||
/*integral_constant_expression_p=*/true);
|
||||
}
|
||||
|
||||
/* Simplify EXPR if it is a non-dependent expression. Returns the
|
||||
(possibly simplified) expression. */
|
||||
/* Instantiate the non-dependent expression EXPR. */
|
||||
|
||||
tree
|
||||
instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
|
||||
|
@ -6374,16 +6371,10 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
|
|||
if (expr == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
|
||||
/* If we're in a template, but EXPR isn't value dependent, simplify
|
||||
it. We're supposed to treat:
|
||||
|
||||
template <typename T> void f(T[1 + 1]);
|
||||
template <typename T> void f(T[2]);
|
||||
|
||||
as two declarations of the same function, for example. */
|
||||
if (processing_template_decl
|
||||
&& is_nondependent_constant_expression (expr))
|
||||
if (processing_template_decl)
|
||||
{
|
||||
/* The caller should have checked this already. */
|
||||
gcc_checking_assert (!instantiation_dependent_uneval_expression_p (expr));
|
||||
processing_template_decl_sentinel s;
|
||||
expr = instantiate_non_dependent_expr_internal (expr, complain);
|
||||
}
|
||||
|
@ -6396,8 +6387,8 @@ instantiate_non_dependent_expr (tree expr)
|
|||
return instantiate_non_dependent_expr_sfinae (expr, tf_error);
|
||||
}
|
||||
|
||||
/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
|
||||
an uninstantiated expression. */
|
||||
/* Like instantiate_non_dependent_expr, but return NULL_TREE if the
|
||||
expression is dependent or non-constant. */
|
||||
|
||||
tree
|
||||
instantiate_non_dependent_or_null (tree expr)
|
||||
|
|
|
@ -11217,6 +11217,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
|
|||
/* decltype is an unevaluated context. */
|
||||
cp_unevaluated u;
|
||||
|
||||
processing_template_decl_sentinel ptds (/*reset=*/false);
|
||||
|
||||
/* Depending on the resolution of DR 1172, we may later need to distinguish
|
||||
instantiation-dependent but not type-dependent expressions so that, say,
|
||||
A<decltype(sizeof(T))>::U doesn't require 'typename'. */
|
||||
|
@ -11235,6 +11237,10 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
|
|||
expr = instantiate_non_dependent_expr_sfinae (expr, complain);
|
||||
if (expr == error_mark_node)
|
||||
return error_mark_node;
|
||||
/* Keep processing_template_decl cleared for the rest of the function
|
||||
(for sake of the call to lvalue_kind below, which handles templated
|
||||
and non-templated COND_EXPR differently). */
|
||||
processing_template_decl = 0;
|
||||
}
|
||||
|
||||
/* The type denoted by decltype(e) is defined as follows: */
|
||||
|
|
6
gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
Normal file
6
gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
Normal file
|
@ -0,0 +1,6 @@
|
|||
// PR c++/104823
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct S { S(int); };
|
||||
double id(double);
|
||||
template<class> auto f(double v) -> decltype(S{id(v)}); // { dg-error "narrowing" }
|
14
gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
Normal file
14
gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Verify we correctly handle the non-dependent attribute expression which
|
||||
// which we used to reject due to double folding.
|
||||
// { dg-do compile { target { c++11 } } }
|
||||
|
||||
struct A {
|
||||
constexpr int f() const { return __alignof__(int); };
|
||||
};
|
||||
|
||||
template<class...>
|
||||
void f() {
|
||||
int a __attribute__((aligned(A{}.f())));
|
||||
}
|
||||
|
||||
template void f();
|
Loading…
Add table
Reference in a new issue