re PR c++/56041 (Constexpr conversion function definition not found in template argument context)

PR c++/56041
	* cp-tree.h (struct processing_template_decl_sentinel): New.
	* pt.c (instantiate_non_dependent_expr_internal): Split out from...
	(instantiate_non_dependent_expr_sfinae): Here.
	(convert_nontype_argument): Use them.
	* constexpr.c (fold_non_dependent_expr): Use them.

From-SVN: r217823
This commit is contained in:
Jason Merrill 2014-11-19 22:25:26 -05:00 committed by Jason Merrill
parent 9d39384c6b
commit 1b5695e610
5 changed files with 96 additions and 26 deletions

View File

@ -1,5 +1,12 @@
2014-11-19 Jason Merrill <jason@redhat.com>
PR c++/56041
* cp-tree.h (struct processing_template_decl_sentinel): New.
* pt.c (instantiate_non_dependent_expr_internal): Split out from...
(instantiate_non_dependent_expr_sfinae): Here.
(convert_nontype_argument): Use them.
* constexpr.c (fold_non_dependent_expr): Use them.
PR c++/63885
* constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't
complain yet about a reference.

View File

@ -3506,17 +3506,8 @@ fold_non_dependent_expr (tree t)
if (!instantiation_dependent_expression_p (t)
&& potential_constant_expression (t))
{
HOST_WIDE_INT saved_processing_template_decl;
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
t = tsubst_copy_and_build (t,
/*args=*/NULL_TREE,
tf_none,
/*in_decl=*/NULL_TREE,
/*function_p=*/false,
/*integral_constant_expression_p=*/true);
processing_template_decl = saved_processing_template_decl;
processing_template_decl_sentinel s;
t = instantiate_non_dependent_expr_internal (t, tf_none);
if (type_unknown_p (t)
|| BRACE_ENCLOSED_INITIALIZER_P (t))

View File

@ -1082,6 +1082,8 @@ struct GTY(()) saved_scope {
struct saved_scope *prev;
};
extern GTY(()) struct saved_scope *scope_chain;
/* The current open namespace. */
#define current_namespace scope_chain->old_namespace
@ -1123,6 +1125,24 @@ struct GTY(()) saved_scope {
#define processing_specialization scope_chain->x_processing_specialization
#define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
/* RAII sentinel to handle clearing processing_template_decl and restoring
it when done. */
struct processing_template_decl_sentinel
{
int saved;
processing_template_decl_sentinel (bool reset = true)
: saved (processing_template_decl)
{
if (reset)
processing_template_decl = 0;
}
~processing_template_decl_sentinel()
{
processing_template_decl = saved;
}
};
/* The cached class binding level, from the most recently exited
class, or NULL if none. */
@ -1140,8 +1160,6 @@ struct GTY(()) saved_scope {
/* A list of private types mentioned, for deferred access checking. */
extern GTY(()) struct saved_scope *scope_chain;
struct GTY((for_user)) cxx_int_tree_map {
unsigned int uid;
tree to;
@ -5716,6 +5734,7 @@ extern void make_args_non_dependent (vec<tree, va_gc> *);
extern bool reregister_specialization (tree, tree, tree);
extern tree instantiate_non_dependent_expr (tree);
extern tree instantiate_non_dependent_expr_sfinae (tree, tsubst_flags_t);
extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
extern bool alias_type_or_template_p (tree);
extern bool alias_template_specialization_p (const_tree);
extern bool dependent_alias_template_spec_p (const_tree);

View File

@ -5212,6 +5212,24 @@ redeclare_class_template (tree type, tree parms)
return true;
}
/* 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))
and cleared processing_template_decl. */
tree
instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
{
return tsubst_copy_and_build (expr,
/*args=*/NULL_TREE,
complain,
/*in_decl=*/NULL_TREE,
/*function_p=*/false,
/*integral_constant_expression_p=*/true);
}
/* Simplify EXPR if it is a non-dependent expression. Returns the
(possibly simplified) expression. */
@ -5232,17 +5250,8 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
&& !instantiation_dependent_expression_p (expr)
&& potential_constant_expression (expr))
{
HOST_WIDE_INT saved_processing_template_decl;
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
expr = tsubst_copy_and_build (expr,
/*args=*/NULL_TREE,
complain,
/*in_decl=*/NULL_TREE,
/*function_p=*/false,
/*integral_constant_expression_p=*/true);
processing_template_decl = saved_processing_template_decl;
processing_template_decl_sentinel s;
expr = instantiate_non_dependent_expr_internal (expr, complain);
}
return expr;
}
@ -5736,11 +5745,15 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
so that access checking can be performed when the template is
instantiated -- but here we need the resolved form so that we can
convert the argument. */
bool non_dep = false;
if (TYPE_REF_OBJ_P (type)
&& has_value_dependent_address (expr))
/* If we want the address and it's value-dependent, don't fold. */;
else if (!type_unknown_p (expr))
expr = instantiate_non_dependent_expr_sfinae (expr, complain);
else if (!type_unknown_p (expr)
&& processing_template_decl
&& !instantiation_dependent_expression_p (expr)
&& potential_constant_expression (expr))
non_dep = true;
if (error_operand_p (expr))
return error_mark_node;
expr_type = TREE_TYPE (expr);
@ -5749,6 +5762,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
else
expr = mark_rvalue_use (expr);
/* If the argument is non-dependent, perform any conversions in
non-dependent context as well. */
processing_template_decl_sentinel s (non_dep);
if (non_dep)
expr = instantiate_non_dependent_expr_internal (expr, complain);
/* 14.3.2/5: The null pointer{,-to-member} conversion is applied
to a non-type argument of "nullptr". */
if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))

View File

@ -0,0 +1,34 @@
// PR c++/56041
// { dg-do compile { target c++11 } }
template< class T, T v >
struct integral_constant
{
using type = integral_constant<T,v>;
using value_type = T;
static constexpr T value = v;
constexpr operator T ( ) noexcept { return value; }
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
template< bool b, class T = void > struct enable_if { using type = T; };
template< class T > struct enable_if<false, T> { };
template< class T,
class = typename enable_if< true_type{} // should compile; doesn't
, T>::type
>
T try_it( ) { return T{}; }
int main( )
{
static_assert( true_type{} , "failed test 1!" );
static_assert( true_type{} , "failed test 2!" );
static_assert( ! false_type{} , "failed test 3!" );
static_assert( !! true_type{} , "failed test 4!" );
return try_it<int>();
}