Commit 4be5c72c by Jason Merrill Committed by Jason Merrill

Implement P0732R2, class types in non-type template parameters.

There is one significant piece of this that is not implemented yet: the
reliance on defaulted operator<=>, which someone else has been working on.
So, for the moment those lines are commented out of the testcases.

One tricky bit was treating template parameters of classtype as const
lvalues without making their decltype const; for this I used a
VIEW_CONVERT_EXPR wrapper, which previously could only appear in templates
as location wrappers.

The user-defined literal parts of P0732R2 are in the next patch.

gcc/cp/
	* error.c (dump_simple_decl): Look through a template parm object.
	* mangle.c (write_template_arg): Likewise.
	(mangle_template_parm_object): New.
	* pt.c (template_parm_object_p, get_template_parm_object): New.
	(invalid_tparm_referent_p): Factor from convert_nontype_argument.
	(convert_nontype_argument, invalid_nontype_parm_type_p): Handle
	class-type template arguments.
	* tree.c (lvalue_kind): Likewise.
gcc/c-family/
	* c-cppbuiltin.c (c_cpp_builtins): Add
	__cpp_nontype_template_parameter_class.
libiberty/
	* cp-demangle.c (d_dump, d_make_comp, d_count_templates_scopes)
	(d_print_comp_inner): Handle DEMANGLE_COMPONENT_TPARM_OBJ.
	(d_special_name): Handle TA.
	(d_expresion_1): Fix demangling of brace-enclosed initializer list.
include/
	* demangle.h (enum demangle_component_type): Add
	DEMANGLE_COMPONENT_TPARM_OBJ.

From-SVN: r265789
parent 5dab8b11
2018-10-19 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.c (c_cpp_builtins): Add
__cpp_nontype_template_parameter_class.
2018-10-31 Nathan Sidwell <nathan@acm.org>
* c-opts.c (c_finish_options): Force command line macro
......
......@@ -979,6 +979,7 @@ c_cpp_builtins (cpp_reader *pfile)
{
/* Set feature test macros for C++2a. */
cpp_define (pfile, "__cpp_explicit_bool=201806");
cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806");
}
if (flag_concepts)
cpp_define (pfile, "__cpp_concepts=201507");
......
2018-11-04 Jason Merrill <jason@redhat.com>
Implement P0732R2, class types in non-type template parameters.
* error.c (dump_simple_decl): Look through a template parm object.
* mangle.c (write_template_arg): Likewise.
(mangle_template_parm_object): New.
* pt.c (template_parm_object_p, get_template_parm_object): New.
(invalid_tparm_referent_p): Factor from convert_nontype_argument.
(convert_nontype_argument, invalid_nontype_parm_type_p): Handle
class-type template arguments.
* tree.c (lvalue_kind): Likewise.
* cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
* constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
(cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
......
......@@ -6746,6 +6746,7 @@ extern bool variable_template_specialization_p (tree);
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);
extern bool template_parm_object_p (const_tree);
extern bool explicit_class_specialization_p (tree);
extern bool push_tinst_level (tree);
extern bool push_tinst_level_loc (tree, location_t);
......@@ -7446,6 +7447,7 @@ extern tree mangle_tls_init_fn (tree);
extern tree mangle_tls_wrapper_fn (tree);
extern bool decl_tls_wrapper_p (tree);
extern tree mangle_ref_init_variable (tree);
extern tree mangle_template_parm_object (tree);
extern char * get_mangled_vtable_map_var_name (tree);
extern bool mangle_return_type_p (tree);
extern tree mangle_decomp (tree, vec<tree> &);
......
......@@ -1006,6 +1006,9 @@ dump_global_iord (cxx_pretty_printer *pp, tree t)
static void
dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
{
if (template_parm_object_p (t))
return dump_expr (pp, DECL_INITIAL (t), flags);
if (flags & TFF_DECL_SPECIFIERS)
{
if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
......
......@@ -3437,6 +3437,10 @@ write_template_arg (tree node)
}
}
if (template_parm_object_p (node))
/* We want to mangle the argument, not the var we stored it in. */
node = DECL_INITIAL (node);
/* Strip a conversion added by convert_nontype_argument. */
if (TREE_CODE (node) == IMPLICIT_CONV_EXPR)
node = TREE_OPERAND (node, 0);
......@@ -4257,6 +4261,19 @@ mangle_ref_init_variable (const tree variable)
write_unsigned_number (temp_count++);
return finish_mangling_get_identifier ();
}
/* Return an identifier for the mangled name of a C++20 template parameter
object for template argument EXPR. */
tree
mangle_template_parm_object (tree expr)
{
start_mangling (expr);
write_string ("_ZTAX");
write_expression (expr);
write_char ('E');
return finish_mangling_get_identifier ();
}
/* Given a CLASS_TYPE, such as a record for std::bad_exception this
function generates a mangled name for the vtable map variable of
......
......@@ -3648,8 +3648,17 @@ finish_id_expression (tree id_expression,
*idk = CP_ID_KIND_NONE;
if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
decl = TEMPLATE_PARM_DECL (decl);
r = convert_from_reference (DECL_INITIAL (decl));
r = DECL_INITIAL (decl);
if (CLASS_TYPE_P (TREE_TYPE (r)) && !CP_TYPE_CONST_P (TREE_TYPE (r)))
{
/* If the entity is a template parameter object for a template
parameter of type T, the type of the expression is const T. */
tree ctype = TREE_TYPE (r);
ctype = cp_build_qualified_type (ctype, (cp_type_quals (ctype)
| TYPE_QUAL_CONST));
r = build1 (VIEW_CONVERT_EXPR, ctype, r);
}
r = convert_from_reference (r);
if (integral_constant_expression_p
&& !dependent_type_p (TREE_TYPE (decl))
&& !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r))))
......@@ -8802,7 +8811,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
if (identifier_p (expr))
expr = lookup_name (expr);
if (INDIRECT_REF_P (expr))
if (INDIRECT_REF_P (expr)
|| TREE_CODE (expr) == VIEW_CONVERT_EXPR)
/* This can happen when the expression is, e.g., "a.b". Just
look at the underlying operand. */
expr = TREE_OPERAND (expr, 0);
......
......@@ -280,6 +280,12 @@ lvalue_kind (const_tree ref)
case PAREN_EXPR:
return lvalue_kind (TREE_OPERAND (ref, 0));
case TEMPLATE_PARM_INDEX:
if (CLASS_TYPE_P (TREE_TYPE (ref)))
/* A template parameter object is an lvalue. */
return clk_ordinary;
return clk_none;
default:
default_:
if (!TREE_TYPE (ref))
......
......@@ -416,6 +416,12 @@
# error "__cpp_variadic_using != 201611"
#endif
// C++20 features
#if __cpp_nontype_template_parameter_class != 201806
# error "__cpp_nontype_template_parameter_class != 201806"
#endif
#ifdef __has_cpp_attribute
# if ! __has_cpp_attribute(maybe_unused)
......
// { dg-do compile { target c++2a } }
struct A
{
int i;
constexpr A (int i): i(i) {}
// auto operator<=> (const A&) = default;
};
template <A a>
struct B
{
static constexpr int i = a.i;
static constexpr A const* ap = &a;
};
template <A a>
struct C
{
static constexpr A const* ap = &a;
};
static_assert(B<1>::i == 1);
static_assert(B<2>::i == 2);
static_assert(B<1>::ap == C<1>::ap);
static_assert(B<1>::ap != C<2>::ap);
// { dg-final { scan-assembler "_Z1fP1BIXtl1ALi1EEEE" } }
// { dg-final { scan-assembler "_ZTAXtl1ALi1EEE" } }
const void* f(B<1> *p) {
constexpr int i = p->ap->i;
return p->ap;
}
// { dg-do compile { target c++2a } }
struct A {
int i;
// auto operator<=> (const A&) = default;
};
template <typename T, T t> void f()
{
g(t); // { dg-error "not declared" }
}
int main()
{
f<A,A{1}>();
}
// { dg-message "T t = A{1}" "" { target *-*-* } 0 }
// { dg-do compile { target c++2a } }
struct A {
int i;
// auto operator<=> (const A&) = default;
};
template <A a> void g();
template <auto t> void f()
{
g<t>();
}
int main()
{
f<A{1}>();
}
// { dg-do compile { target c++2a } }
template <class T>
struct A {
constexpr A(T) {}
// auto operator<=> (const A&) = default;
};
template <A a> void f();
int main()
{
constexpr A a = 1;
f<a>();
f<1>();
}
// { dg-final { scan-assembler "_Z1fIXtl1AIiEEEEvv" } }
// { dg-final { scan-assembler-not "_Z1fIXtlK1AIiEEEEvv" } }
// Example from P0732
// { dg-do compile { target c++2a } }
template<class T, T p> class X {
/* ... */
};
struct A {
constexpr A(const char*) {}
// auto operator<=> (const A&) = default;
};
X<A, "Pyrophoricity"> x3; // OK: string literal is a constructor argument to A
// Example from P0732.
// { dg-do compile { target c++2a } }
namespace std {
using size_t = decltype(sizeof(1));
template <typename CharT, std::size_t N>
struct basic_fixed_string
{
constexpr basic_fixed_string(const CharT (&foo)[N+1])
: m_data()
{
for (int i = 0; i <= N; ++i)
m_data[i] = foo[i];
}
// auto operator<=>(const basic_fixed_string &) = default;
CharT m_data[N+1];
};
template <typename CharT, std::size_t N>
basic_fixed_string(const CharT (&str)[N])->basic_fixed_string<CharT, N-1>;
template <std::size_t N>
using fixed_string = basic_fixed_string<char, N>;
}
template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;
// If the entity is a template parameter object for a template parameter of
// type T, the type of the expression is const T.
// { dg-do compile { target c++2a } }
template <class T, class U> struct same;
template <class T> struct same<T,T> {};
struct A {
int i;
// auto operator<=> (const A&) = default;
};
void f(A&) = delete;
void f(const A&) { }
template < A a > struct B
{
B()
{
f(a);
same<A,decltype(a)> s;
same<const A&,decltype((a))> s2;
}
};
B<A{42}> b;
//PR c++/27668
template<typename class T, T = T()> // { dg-error "nested-name-specifier|two or more|valid type" }
template<typename class T, T = T()> // { dg-error "nested-name-specifier|two or more|class type|incomplete" }
// { dg-error "cast" "" { target c++98_only } .-1 }
struct A {};
......
......@@ -5,5 +5,5 @@ template<int> struct A
template<typename> void foo();
};
template<> template<struct T> void A<0>::foo() {} // { dg-error "not a valid type" }
template<> template<struct T> void A<0>::foo() {} // { dg-error "class type|incomplete" }
......@@ -8,7 +8,7 @@
template <int> struct A
{
typedef A<0> B; // { dg-message "previous declaration" }
template <B> struct B {}; // { dg-error "not a valid type|typedef" }
template <B> struct B {}; // { dg-error "class type|incomplete|typedef" }
};
A<0> a;
......@@ -8,7 +8,7 @@
template <int> struct A
{
typedef A<0> B;
template <B> struct C {}; // { dg-error "not a valid type" }
template <B> struct C {}; // { dg-error "class type|incomplete" }
};
A<0> a;
......@@ -3,6 +3,6 @@
struct A {};
template<A, typename T> int operator-(A, T); // { dg-error "not a valid type" }
template<A, typename T> int operator-(A, T); // { dg-error "class type" "" { target c++17_down } }
int i = A() - 0; // { dg-error "no match" }
2018-10-19 Jason Merrill <jason@redhat.com>
* demangle.h (enum demangle_component_type): Add
DEMANGLE_COMPONENT_TPARM_OBJ.
2018-10-29 David Malcolm <dmalcolm@redhat.com>
* unique-ptr.h (gnu::move): Generalize so it applies to all
......
......@@ -392,6 +392,9 @@ enum demangle_component_type
template argument, and the right subtree is either NULL or
another TEMPLATE_ARGLIST node. */
DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
/* A template parameter object (C++20). The left subtree is the
corresponding template argument. */
DEMANGLE_COMPONENT_TPARM_OBJ,
/* An initializer list. The left subtree is either an explicit type or
NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */
DEMANGLE_COMPONENT_INITIALIZER_LIST,
......
2018-10-23 Jason Merrill <jason@redhat.com>
Implement P0732R2, class types in non-type template parameters.
* cp-demangle.c (d_dump, d_make_comp, d_count_templates_scopes)
(d_print_comp_inner): Handle DEMANGLE_COMPONENT_TPARM_OBJ.
(d_special_name): Handle TA.
(d_expresion_1): Fix demangling of brace-enclosed initializer list.
2018-10-31 Joseph Myers <joseph@codesourcery.com>
PR bootstrap/82856
......
......@@ -625,6 +625,9 @@ d_dump (struct demangle_component *dc, int indent)
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
printf ("template parameter %ld\n", dc->u.s_number.number);
return;
case DEMANGLE_COMPONENT_TPARM_OBJ:
printf ("template parameter object\n");
break;
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
printf ("function parameter %ld\n", dc->u.s_number.number);
return;
......@@ -1007,6 +1010,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
case DEMANGLE_COMPONENT_NULLARY:
case DEMANGLE_COMPONENT_TRINARY_ARG2:
case DEMANGLE_COMPONENT_TPARM_OBJ:
if (left == NULL)
return NULL;
break;
......@@ -2007,6 +2011,7 @@ d_java_resource (struct d_info *di)
::= TT <type>
::= TI <type>
::= TS <type>
::= TA <template-arg>
::= GV <(object) name>
::= T <call-offset> <(base) encoding>
::= Tc <call-offset> <call-offset> <(base) encoding>
......@@ -2099,6 +2104,10 @@ d_special_name (struct d_info *di)
return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
d_name (di), NULL);
case 'A':
return d_make_comp (di, DEMANGLE_COMPONENT_TPARM_OBJ,
d_template_arg (di), NULL);
default:
return NULL;
}
......@@ -3327,11 +3336,11 @@ d_expression_1 (struct d_info *di)
{
/* Brace-enclosed initializer list, untyped or typed. */
struct demangle_component *type = NULL;
d_advance (di, 2);
if (peek == 't')
type = cplus_demangle_type (di);
if (!d_peek_next_char (di))
return NULL;
d_advance (di, 2);
return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
type, d_exprlist (di, 'E'));
}
......@@ -4101,6 +4110,7 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
case DEMANGLE_COMPONENT_VECTOR_TYPE:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
case DEMANGLE_COMPONENT_TPARM_OBJ:
case DEMANGLE_COMPONENT_INITIALIZER_LIST:
case DEMANGLE_COMPONENT_CAST:
case DEMANGLE_COMPONENT_CONVERSION:
......@@ -4872,6 +4882,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
}
return;
case DEMANGLE_COMPONENT_TPARM_OBJ:
d_append_string (dpi, "template parameter object for ");
d_print_comp (dpi, options, d_left (dc));
return;
case DEMANGLE_COMPONENT_CTOR:
d_print_comp (dpi, options, dc->u.s_ctor.name);
return;
......
......@@ -4667,6 +4667,12 @@ void eat<int*, Foo()::{lambda(auto:1*, auto:2*)#6}>(int*&, Foo()::{lambda(auto:1
_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E0_EvRS3_RS5_
void eat<int*, Bar<short>()::{lambda(short*, auto:1*, auto:2*)#2}>(int*&, Bar<short>()::{lambda(short*, auto:1*, auto:2*)#2}&)
_Z1fP1BIXtl1ALi1EEEE
f(B<A{1}>*)
_ZTAXtl1ALi1EEE
template parameter object for A{1}
# PR 77489
_ZZ3foovE8localVar_9
foo()::localVar
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment