Implement constexpr variable templates
Implement constexpr variable templates * decl.c (grokvardecl): Handle specializations of variable templates. (grokdeclarator): Handle variable template id expressions and NULL_TREE return from grokvardecl. * decl2.c (check_member_template): Allow declaration of template member variables. * parser.c (cp_parser_template_id): Build a TEMPLATE_ID_EXPR for variable templates. * pt.c (check_template_variable): Accept variable temploids at non-class scope. (push_template_decl_real): The current instantiation of a template can be a VAR_DECL. (determine_specialization): Accept variable templates. (check_explicit_specialization): Handle and check for malformed variable template specializations. (lookup_template_variable): New. (tsubst_decl): Handle variable template specializations. (do_decl_instantiation): Handle template variables. (instantiate_decl): Handle template variables. * semantics.c (finish_template_variable): New. (finish_id_expression): Instantiate variable templates. * cp-tree.h (variable_template_p): New. From-SVN: r213641
This commit is contained in:
parent
d406ae470c
commit
4a4f287dc1
@ -1,3 +1,28 @@
|
||||
2014-08-01 Braden Obrzut <admin@maniacsvault.net>
|
||||
|
||||
Implement constexpr variable templates
|
||||
* decl.c (grokvardecl): Handle specializations of variable templates.
|
||||
(grokdeclarator): Handle variable template id expressions and NULL_TREE
|
||||
return from grokvardecl.
|
||||
* decl2.c (check_member_template): Allow declaration of template member
|
||||
variables.
|
||||
* parser.c (cp_parser_template_id): Build a TEMPLATE_ID_EXPR for
|
||||
variable templates.
|
||||
* pt.c (check_template_variable): Accept variable temploids at
|
||||
non-class scope.
|
||||
(push_template_decl_real): The current instantiation of a template
|
||||
can be a VAR_DECL.
|
||||
(determine_specialization): Accept variable templates.
|
||||
(check_explicit_specialization): Handle and check for malformed
|
||||
variable template specializations.
|
||||
(lookup_template_variable): New.
|
||||
(tsubst_decl): Handle variable template specializations.
|
||||
(do_decl_instantiation): Handle template variables.
|
||||
(instantiate_decl): Handle template variables.
|
||||
* semantics.c (finish_template_variable): New.
|
||||
(finish_id_expression): Instantiate variable templates.
|
||||
* cp-tree.h (variable_template_p): New.
|
||||
|
||||
2014-08-02 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
PR c++/15339
|
||||
|
@ -5045,6 +5045,17 @@ class_of_this_parm (const_tree fntype)
|
||||
return TREE_TYPE (type_of_this_parm (fntype));
|
||||
}
|
||||
|
||||
/* True if T designates a variable template declaration. */
|
||||
inline bool
|
||||
variable_template_p (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) != TEMPLATE_DECL)
|
||||
return false;
|
||||
if (tree r = DECL_TEMPLATE_RESULT (t))
|
||||
return VAR_P (r);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* A parameter list indicating for a function with no parameters,
|
||||
e.g "int f(void)". */
|
||||
extern cp_parameter_declarator *no_parameters;
|
||||
@ -5572,6 +5583,7 @@ extern bool redeclare_class_template (tree, tree);
|
||||
extern tree lookup_template_class (tree, tree, tree, tree,
|
||||
int, tsubst_flags_t);
|
||||
extern tree lookup_template_function (tree, tree);
|
||||
extern tree lookup_template_variable (tree, tree);
|
||||
extern int uses_template_parms (tree);
|
||||
extern int uses_template_parms_level (tree, int);
|
||||
extern bool in_template_function (void);
|
||||
@ -5834,6 +5846,7 @@ extern tree perform_koenig_lookup (tree, vec<tree, va_gc> *,
|
||||
tsubst_flags_t);
|
||||
extern tree finish_call_expr (tree, vec<tree, va_gc> **, bool,
|
||||
bool, tsubst_flags_t);
|
||||
extern tree finish_template_variable (tree);
|
||||
extern tree finish_increment_expr (tree, enum tree_code);
|
||||
extern tree finish_this_expr (void);
|
||||
extern tree finish_pseudo_destructor_expr (tree, tree, tree, location_t);
|
||||
|
@ -80,8 +80,8 @@ static int ambi_op_p (enum tree_code);
|
||||
static int unary_op_p (enum tree_code);
|
||||
static void push_local_name (tree);
|
||||
static tree grok_reference_init (tree, tree, tree, int);
|
||||
static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *,
|
||||
int, int, tree);
|
||||
static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
|
||||
int, int, int, tree);
|
||||
static int check_static_variable_definition (tree, tree);
|
||||
static void record_unknown_type (tree, const char *);
|
||||
static tree builtin_function_1 (tree, tree, bool);
|
||||
@ -7968,9 +7968,11 @@ set_linkage_for_static_data_member (tree decl)
|
||||
static tree
|
||||
grokvardecl (tree type,
|
||||
tree name,
|
||||
tree orig_declarator,
|
||||
const cp_decl_specifier_seq *declspecs,
|
||||
int initialized,
|
||||
int constp,
|
||||
int template_count,
|
||||
tree scope)
|
||||
{
|
||||
tree decl;
|
||||
@ -8000,7 +8002,10 @@ grokvardecl (tree type,
|
||||
|| (TREE_CODE (scope) == NAMESPACE_DECL
|
||||
&& current_lang_name != lang_name_cplusplus)
|
||||
/* Similarly for static data members. */
|
||||
|| TYPE_P (scope)))
|
||||
|| TYPE_P (scope)
|
||||
/* Similarly for explicit specializations. */
|
||||
|| (orig_declarator
|
||||
&& TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)))
|
||||
decl = build_lang_decl (VAR_DECL, name, type);
|
||||
else
|
||||
decl = build_decl (input_location, VAR_DECL, name, type);
|
||||
@ -8068,7 +8073,12 @@ grokvardecl (tree type,
|
||||
else
|
||||
DECL_INTERFACE_KNOWN (decl) = 1;
|
||||
|
||||
return decl;
|
||||
// Handle explicit specializations and instantiations of variable templates.
|
||||
if (orig_declarator)
|
||||
decl = check_explicit_specialization (orig_declarator, decl,
|
||||
template_count, 0);
|
||||
|
||||
return decl != error_mark_node ? decl : NULL_TREE;
|
||||
}
|
||||
|
||||
/* Create and return a canonical pointer to member function type, for
|
||||
@ -8962,8 +8972,13 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
dname = fns;
|
||||
if (!identifier_p (dname))
|
||||
{
|
||||
gcc_assert (is_overloaded_fn (dname));
|
||||
dname = DECL_NAME (get_first_fn (dname));
|
||||
if (variable_template_p (dname))
|
||||
dname = DECL_NAME (dname);
|
||||
else
|
||||
{
|
||||
gcc_assert (is_overloaded_fn (dname));
|
||||
dname = DECL_NAME (get_first_fn (dname));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Fall through. */
|
||||
@ -10004,7 +10019,8 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
|
||||
if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR
|
||||
&& TREE_CODE (type) != FUNCTION_TYPE
|
||||
&& TREE_CODE (type) != METHOD_TYPE)
|
||||
&& TREE_CODE (type) != METHOD_TYPE
|
||||
&& !variable_template_p (TREE_OPERAND (unqualified_id, 0)))
|
||||
{
|
||||
error ("template-id %qD used as a declarator",
|
||||
unqualified_id);
|
||||
@ -10894,11 +10910,15 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
/* It's a variable. */
|
||||
|
||||
/* An uninitialized decl with `extern' is a reference. */
|
||||
decl = grokvardecl (type, unqualified_id,
|
||||
decl = grokvardecl (type, dname, unqualified_id,
|
||||
declspecs,
|
||||
initialized,
|
||||
(type_quals & TYPE_QUAL_CONST) != 0,
|
||||
template_count,
|
||||
ctype ? ctype : in_namespace);
|
||||
if (decl == NULL_TREE)
|
||||
return error_mark_node;
|
||||
|
||||
bad_specifiers (decl, BSP_VAR, virtualp,
|
||||
memfn_quals != TYPE_UNQUALIFIED,
|
||||
inlinep, friendp, raises != NULL_TREE);
|
||||
|
@ -524,6 +524,8 @@ check_member_template (tree tmpl)
|
||||
with member templates. */
|
||||
DECL_IGNORED_P (tmpl) = 1;
|
||||
}
|
||||
else if (variable_template_p (tmpl))
|
||||
/* OK */;
|
||||
else
|
||||
error ("template declaration of %q#D", decl);
|
||||
}
|
||||
|
@ -13646,6 +13646,10 @@ cp_parser_template_id (cp_parser *parser,
|
||||
template_id
|
||||
= finish_template_type (templ, arguments, entering_scope);
|
||||
}
|
||||
else if (variable_template_p (templ))
|
||||
{
|
||||
template_id = lookup_template_variable (templ, arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If it's not a class-template or a template-template, it should be
|
||||
|
90
gcc/cp/pt.c
90
gcc/cp/pt.c
@ -1878,11 +1878,16 @@ determine_specialization (tree template_id,
|
||||
if (BASELINK_P (fns))
|
||||
fns = BASELINK_FUNCTIONS (fns);
|
||||
|
||||
if (!is_overloaded_fn (fns))
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL && !is_overloaded_fn (fns))
|
||||
{
|
||||
error ("%qD is not a function template", fns);
|
||||
return error_mark_node;
|
||||
}
|
||||
else if (VAR_P (decl) && !variable_template_p (fns))
|
||||
{
|
||||
error ("%qD is not a variable template", fns);
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* Count the number of template headers specified for this
|
||||
specialization. */
|
||||
@ -1892,7 +1897,9 @@ determine_specialization (tree template_id,
|
||||
b = b->level_chain)
|
||||
++header_count;
|
||||
|
||||
for (; fns; fns = OVL_NEXT (fns))
|
||||
if (variable_template_p (fns))
|
||||
templates = tree_cons (explicit_targs, fns, templates);
|
||||
else for (; fns; fns = OVL_NEXT (fns))
|
||||
{
|
||||
tree fn = OVL_CURRENT (fns);
|
||||
|
||||
@ -2308,9 +2315,16 @@ check_template_variable (tree decl)
|
||||
tree ctx = CP_DECL_CONTEXT (decl);
|
||||
int wanted = num_template_headers_for_class (ctx);
|
||||
if (!TYPE_P (ctx) || !CLASSTYPE_TEMPLATE_INFO (ctx))
|
||||
permerror (DECL_SOURCE_LOCATION (decl),
|
||||
"%qD is not a static data member of a class template", decl);
|
||||
else if (template_header_count > wanted)
|
||||
{
|
||||
if (cxx_dialect < cxx1y)
|
||||
pedwarn (DECL_SOURCE_LOCATION (decl), 0,
|
||||
"variable templates only available with "
|
||||
"-std=c++1y or -std=gnu++1y");
|
||||
|
||||
// Namespace-scope variable templates should have a template header.
|
||||
++wanted;
|
||||
}
|
||||
if (template_header_count > wanted)
|
||||
{
|
||||
bool warned = pedwarn (DECL_SOURCE_LOCATION (decl), 0,
|
||||
"too many template headers for %D (should be %d)",
|
||||
@ -2442,6 +2456,13 @@ check_explicit_specialization (tree declarator,
|
||||
|
||||
/* Fall through. */
|
||||
case tsk_expl_spec:
|
||||
if (VAR_P (decl) && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
|
||||
{
|
||||
// In cases like template<> constexpr bool v = true;
|
||||
error ("%qD is not a template variable", dname);
|
||||
break;
|
||||
}
|
||||
|
||||
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
|
||||
if (ctype)
|
||||
member_specialization = 1;
|
||||
@ -2481,7 +2502,10 @@ check_explicit_specialization (tree declarator,
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
if (specialization || member_specialization)
|
||||
if ((specialization || member_specialization)
|
||||
/* This doesn't apply to variable templates. */
|
||||
&& (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE
|
||||
|| TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE))
|
||||
{
|
||||
tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
||||
for (; t; t = TREE_CHAIN (t))
|
||||
@ -2566,6 +2590,10 @@ check_explicit_specialization (tree declarator,
|
||||
else if (ctype != NULL_TREE
|
||||
&& (identifier_p (TREE_OPERAND (declarator, 0))))
|
||||
{
|
||||
// Ignore variable templates.
|
||||
if (VAR_P (decl))
|
||||
return decl;
|
||||
|
||||
/* Find the list of functions in ctype that have the same
|
||||
name as the declared function. */
|
||||
tree name = TREE_OPERAND (declarator, 0);
|
||||
@ -2691,7 +2719,8 @@ check_explicit_specialization (tree declarator,
|
||||
/* If we thought that the DECL was a member function, but it
|
||||
turns out to be specializing a static member function,
|
||||
make DECL a static member function as well. */
|
||||
if (DECL_STATIC_FUNCTION_P (tmpl)
|
||||
if (DECL_FUNCTION_TEMPLATE_P (tmpl)
|
||||
&& DECL_STATIC_FUNCTION_P (tmpl)
|
||||
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
|
||||
revert_static_member_fn (decl);
|
||||
|
||||
@ -2725,7 +2754,8 @@ check_explicit_specialization (tree declarator,
|
||||
|
||||
/* Inherit default function arguments from the template
|
||||
DECL is specializing. */
|
||||
copy_default_args_to_explicit_spec (decl);
|
||||
if (DECL_FUNCTION_TEMPLATE_P (tmpl))
|
||||
copy_default_args_to_explicit_spec (decl);
|
||||
|
||||
/* This specialization has the same protection as the
|
||||
template it specializes. */
|
||||
@ -2797,6 +2827,7 @@ check_explicit_specialization (tree declarator,
|
||||
|
||||
/* A 'structor should already have clones. */
|
||||
gcc_assert (decl == error_mark_node
|
||||
|| variable_template_p (tmpl)
|
||||
|| !(DECL_CONSTRUCTOR_P (decl)
|
||||
|| DECL_DESTRUCTOR_P (decl))
|
||||
|| DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl)));
|
||||
@ -4741,6 +4772,15 @@ push_template_decl_real (tree decl, bool is_friend)
|
||||
&& TYPE_DECL_ALIAS_P (decl))
|
||||
/* alias-declaration */
|
||||
gcc_assert (!DECL_ARTIFICIAL (decl));
|
||||
else if (VAR_P (decl))
|
||||
{
|
||||
if (!DECL_DECLARED_CONSTEXPR_P (decl))
|
||||
{
|
||||
sorry ("template declaration of non-constexpr variable %qD",
|
||||
decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("template declaration of %q#D", decl);
|
||||
@ -7917,6 +7957,14 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
|
||||
timevar_pop (TV_TEMPLATE_INST);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. */
|
||||
|
||||
tree
|
||||
lookup_template_variable (tree templ, tree arglist)
|
||||
{
|
||||
return build2 (TEMPLATE_ID_EXPR, TREE_TYPE (templ), templ, arglist);
|
||||
}
|
||||
|
||||
struct pair_fn_data
|
||||
{
|
||||
@ -10484,7 +10532,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||
if (PRIMARY_TEMPLATE_P (t))
|
||||
DECL_PRIMARY_TEMPLATE (r) = r;
|
||||
|
||||
if (TREE_CODE (decl) != TYPE_DECL)
|
||||
if (TREE_CODE (decl) != TYPE_DECL && TREE_CODE (decl) != VAR_DECL)
|
||||
/* Record this non-type partial instantiation. */
|
||||
register_specialization (r, t,
|
||||
DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
|
||||
@ -19172,7 +19220,11 @@ do_decl_instantiation (tree decl, tree storage)
|
||||
error ("explicit instantiation of non-template %q#D", decl);
|
||||
return;
|
||||
}
|
||||
else if (VAR_P (decl))
|
||||
|
||||
bool var_templ = (DECL_TEMPLATE_INFO (decl)
|
||||
&& variable_template_p (DECL_TI_TEMPLATE (decl)));
|
||||
|
||||
if (VAR_P (decl) && !var_templ)
|
||||
{
|
||||
/* There is an asymmetry here in the way VAR_DECLs and
|
||||
FUNCTION_DECLs are handled by grokdeclarator. In the case of
|
||||
@ -19201,7 +19253,7 @@ do_decl_instantiation (tree decl, tree storage)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (decl) != FUNCTION_DECL)
|
||||
else if (TREE_CODE (decl) != FUNCTION_DECL && !var_templ)
|
||||
{
|
||||
error ("explicit instantiation of %q#D", decl);
|
||||
return;
|
||||
@ -19906,10 +19958,12 @@ instantiate_decl (tree d, int defer_ok,
|
||||
tree ns;
|
||||
tree init;
|
||||
bool const_init = false;
|
||||
bool enter_context = DECL_CLASS_SCOPE_P (d);
|
||||
|
||||
ns = decl_namespace_context (d);
|
||||
push_nested_namespace (ns);
|
||||
push_nested_class (DECL_CONTEXT (d));
|
||||
if (enter_context)
|
||||
push_nested_class (DECL_CONTEXT (d));
|
||||
init = tsubst_expr (DECL_INITIAL (code_pattern),
|
||||
args,
|
||||
tf_warning_or_error, NULL_TREE,
|
||||
@ -19921,7 +19975,8 @@ instantiate_decl (tree d, int defer_ok,
|
||||
cp_finish_decl (d, init, /*init_const_expr_p=*/const_init,
|
||||
/*asmspec_tree=*/NULL_TREE,
|
||||
LOOKUP_ONLYCONVERTING);
|
||||
pop_nested_class ();
|
||||
if (enter_context)
|
||||
pop_nested_class ();
|
||||
pop_nested_namespace (ns);
|
||||
}
|
||||
|
||||
@ -20018,10 +20073,15 @@ instantiate_decl (tree d, int defer_ok,
|
||||
DECL_EXTERNAL (d) = 0;
|
||||
|
||||
/* Enter the scope of D so that access-checking works correctly. */
|
||||
push_nested_class (DECL_CONTEXT (d));
|
||||
bool enter_context = DECL_CLASS_SCOPE_P (d);
|
||||
if (enter_context)
|
||||
push_nested_class (DECL_CONTEXT (d));
|
||||
|
||||
const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
|
||||
cp_finish_decl (d, init, const_init, NULL_TREE, 0);
|
||||
pop_nested_class ();
|
||||
|
||||
if (enter_context)
|
||||
pop_nested_class ();
|
||||
}
|
||||
else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern))
|
||||
synthesize_method (d);
|
||||
|
@ -2418,6 +2418,15 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */
|
||||
|
||||
tree
|
||||
finish_template_variable (tree var)
|
||||
{
|
||||
return instantiate_template (TREE_OPERAND (var, 0), TREE_OPERAND (var, 1),
|
||||
tf_error);
|
||||
}
|
||||
|
||||
/* Finish a call to a postfix increment or decrement or EXPR. (Which
|
||||
is indicated by CODE, which should be POSTINCREMENT_EXPR or
|
||||
POSTDECREMENT_EXPR.) */
|
||||
@ -3500,6 +3509,11 @@ finish_id_expression (tree id_expression,
|
||||
a call to its wrapper. */
|
||||
decl = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
|
||||
}
|
||||
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
|
||||
&& variable_template_p (TREE_OPERAND (decl, 0)))
|
||||
{
|
||||
decl = finish_template_variable (decl);
|
||||
}
|
||||
else if (scope)
|
||||
{
|
||||
decl = (adjust_result_of_qualified_name_lookup
|
||||
|
@ -1,10 +1,11 @@
|
||||
// PR c++/59638
|
||||
// { dg-do compile { target c++1y } }
|
||||
// { dg-options "" }
|
||||
// { dg-excess-errors "sorry" }
|
||||
|
||||
void (*a)(auto); // { dg-error "template declaration" }
|
||||
void (*a)(auto); // { dg-error "" "" { xfail *-*-* } }
|
||||
|
||||
void (*b)(auto) = 0; // { dg-error "template declaration" }
|
||||
void (*b)(auto) = 0; // { dg-error "" "" { xfail *-*-* } }
|
||||
|
||||
typedef void (*f)(auto); // { dg-error "template declaration" }
|
||||
|
||||
|
22
gcc/testsuite/g++.dg/cpp1y/var-templ1.C
Normal file
22
gcc/testsuite/g++.dg/cpp1y/var-templ1.C
Normal file
@ -0,0 +1,22 @@
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++1y" }
|
||||
|
||||
template<int A, int B>
|
||||
struct S1
|
||||
{
|
||||
static constexpr int a = A;
|
||||
static constexpr int b = B;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr int var = T::a + T::b;
|
||||
|
||||
int main ()
|
||||
{
|
||||
int v = var<S1<199, 23>>/2;
|
||||
return !(
|
||||
var<S1<11, 100>> == v
|
||||
&& var<S1<50, 120>> == var<S1<150, var<S1<10, 10>>>>
|
||||
&& var<S1<53, 23>> != 222
|
||||
);
|
||||
}
|
34
gcc/testsuite/g++.dg/cpp1y/var-templ2.C
Normal file
34
gcc/testsuite/g++.dg/cpp1y/var-templ2.C
Normal file
@ -0,0 +1,34 @@
|
||||
// { dg-do compile }
|
||||
// { dg-options "-std=c++1y" }
|
||||
|
||||
// Template variables and static member variables of template classes are
|
||||
// often confused.
|
||||
|
||||
template<typename T>
|
||||
struct S1
|
||||
{
|
||||
static int n;
|
||||
static int arr[];
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr int var = sizeof (T);
|
||||
|
||||
template<typename T>
|
||||
int S1<T>::n = sizeof (T);
|
||||
|
||||
template<typename T>
|
||||
int S1<T>::arr[sizeof (T)];
|
||||
|
||||
template<>
|
||||
int S1<int>::n = 8;
|
||||
|
||||
template<>
|
||||
int S1<int>::arr[8];
|
||||
|
||||
int main ()
|
||||
{
|
||||
S1<int> v1;
|
||||
var<S1<int>>;
|
||||
return 0;
|
||||
}
|
19
gcc/testsuite/g++.dg/cpp1y/var-templ3.C
Normal file
19
gcc/testsuite/g++.dg/cpp1y/var-templ3.C
Normal file
@ -0,0 +1,19 @@
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++1y" }
|
||||
|
||||
template<typename T>
|
||||
constexpr int var = sizeof (T);
|
||||
|
||||
template<typename T>
|
||||
struct S1
|
||||
{
|
||||
template<typename U>
|
||||
static constexpr int a = sizeof (U) + sizeof (T);
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
return !(
|
||||
var<int> + var<char> == S1<int>::a<char>
|
||||
);
|
||||
}
|
16
gcc/testsuite/g++.dg/cpp1y/var-templ4.C
Normal file
16
gcc/testsuite/g++.dg/cpp1y/var-templ4.C
Normal file
@ -0,0 +1,16 @@
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++1y" }
|
||||
|
||||
template<typename T>
|
||||
constexpr int var = sizeof (T);
|
||||
|
||||
template<>
|
||||
constexpr int var<int> = 100000;
|
||||
|
||||
int main ()
|
||||
{
|
||||
return !(
|
||||
var<int> == 100000
|
||||
&& var<char> == sizeof(char)
|
||||
);
|
||||
}
|
22
gcc/testsuite/g++.dg/cpp1y/var-templ5.C
Normal file
22
gcc/testsuite/g++.dg/cpp1y/var-templ5.C
Normal file
@ -0,0 +1,22 @@
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++1y" }
|
||||
|
||||
template<int A, int B>
|
||||
struct S1
|
||||
{
|
||||
static constexpr int a = A;
|
||||
static constexpr int b = B;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
constexpr int var = T::a + T::b;
|
||||
|
||||
template<template<int,int> class T, int A>
|
||||
constexpr int var2 = var<T<A, A>> + A;
|
||||
|
||||
int main ()
|
||||
{
|
||||
return !(
|
||||
var2<S1, 40> == 120
|
||||
);
|
||||
}
|
@ -15,4 +15,4 @@ struct B
|
||||
static T i;
|
||||
};
|
||||
|
||||
template<> template <> int B<int>::i; // { dg-error "should be 1" }
|
||||
template<> template <> int B<int>::i; // { dg-error "template|should be 1" }
|
||||
|
@ -1,3 +1,3 @@
|
||||
// PR c++/30659
|
||||
|
||||
extern "C" template A<char> foo(); // { dg-error "forbids|static data|expected" }
|
||||
extern "C" template A<char> foo(); // { dg-error "forbids|static data|expected|template" }
|
||||
|
@ -19,4 +19,4 @@ template<> struct A<int> {
|
||||
};
|
||||
|
||||
bool A<int>::a = true; // ok
|
||||
template<> bool A<int>::b = false; // { dg-error "template header" }
|
||||
template<> bool A<int>::b = false; // { dg-error "template (header|variable)" }
|
||||
|
@ -1,4 +1,5 @@
|
||||
// { dg-do assemble }
|
||||
// Origin: Jason Merrill <jason@cygnus.com>
|
||||
// { dg-excess-errors "sorry" }
|
||||
|
||||
template <class T> T t; // { dg-error "" } template declaration of t
|
||||
template <class T> T t; // template declaration of t
|
||||
|
Loading…
Reference in New Issue
Block a user