aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2016-10-21 15:45:45 -0400
committerJason Merrill <jason@gcc.gnu.org>2016-10-21 15:45:45 -0400
commit16b61424dd309f61326f577a6deb8487c6c1f291 (patch)
tree6c7926ef82590c0dc45a976fca3d534b08b3b791 /gcc
parenta7564a05ff6a64cd1536a903e5f5fad50fed6973 (diff)
downloadgcc-16b61424dd309f61326f577a6deb8487c6c1f291.zip
gcc-16b61424dd309f61326f577a6deb8487c6c1f291.tar.gz
gcc-16b61424dd309f61326f577a6deb8487c6c1f291.tar.bz2
re PR c++/77656 (64-bit integral template parameter gets incorrectly sized as 32-bits)
PR c++/77656 * pt.c (convert_template_argument): Call convert_nontype_argument on value-dependent but not type-dependent arguments. (convert_nontype_argument): Handle value-dependent arguments. (canonicalize_expr_argument): New. (deducible_expression, unify): Skip CONVERT_EXPR. * error.c (dump_template_argument): Likewise. * mangle.c (write_expression): Likewise. From-SVN: r241425
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/error.c4
-rw-r--r--gcc/cp/mangle.c7
-rw-r--r--gcc/cp/pt.c94
-rw-r--r--gcc/testsuite/g++.dg/template/crash53.C2
-rw-r--r--gcc/testsuite/g++.dg/template/nontype28.C14
-rw-r--r--gcc/testsuite/g++.dg/template/nontype3.C2
7 files changed, 94 insertions, 38 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3d62d68..d913536 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,14 @@
2016-10-21 Jason Merrill <jason@redhat.com>
+ PR c++/77656
+ * pt.c (convert_template_argument): Call convert_nontype_argument
+ on value-dependent but not type-dependent arguments.
+ (convert_nontype_argument): Handle value-dependent arguments.
+ (canonicalize_expr_argument): New.
+ (deducible_expression, unify): Skip CONVERT_EXPR.
+ * error.c (dump_template_argument): Likewise.
+ * mangle.c (write_expression): Likewise.
+
* ptree.c (cxx_print_xnode) [TEMPLATE_PARM_INDEX]: Dump the decl.
2016-10-21 Jakub Jelinek <jakub@redhat.com>
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 4cf0041..917a448 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -171,6 +171,10 @@ dump_template_argument (cxx_pretty_printer *pp, tree arg, int flags)
if (TREE_CODE (arg) == TREE_LIST)
arg = TREE_VALUE (arg);
+ /* Strip implicit conversions. */
+ while (CONVERT_EXPR_P (arg))
+ arg = TREE_OPERAND (arg, 0);
+
dump_expr (pp, arg, (flags | TFF_EXPR_IN_PARENS) & ~TFF_CLASS_KEY_OR_ENUM);
}
}
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 9f86e91..cb2f260 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2774,10 +2774,9 @@ write_expression (tree expr)
{
enum tree_code code = TREE_CODE (expr);
- /* Skip NOP_EXPRs. They can occur when (say) a pointer argument
- is converted (via qualification conversions) to another
- type. */
- while (TREE_CODE (expr) == NOP_EXPR
+ /* Skip NOP_EXPR and CONVERT_EXPR. They can occur when (say) a pointer
+ argument is converted (via qualification conversions) to another type. */
+ while (CONVERT_EXPR_CODE_P (code)
/* Parentheses aren't mangled. */
|| code == PAREN_EXPR
|| TREE_CODE (expr) == NON_LVALUE_EXPR)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 028025d..aa126a0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -214,6 +214,7 @@ static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
static bool complex_alias_template_p (const_tree tmpl);
static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
+static tree canonicalize_expr_argument (tree, tsubst_flags_t);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
@@ -6297,6 +6298,9 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
if (non_dep)
expr = instantiate_non_dependent_expr_internal (expr, complain);
+ if (value_dependent_expression_p (expr))
+ expr = canonicalize_expr_argument (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))
@@ -6405,7 +6409,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
/* Notice that there are constant expressions like '4 % 0' which
do not fold into integer constants. */
- if (TREE_CODE (expr) != INTEGER_CST)
+ if (TREE_CODE (expr) != INTEGER_CST
+ && !value_dependent_expression_p (expr))
{
if (complain & tf_error)
{
@@ -6452,7 +6457,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
Here, we do not care about functions, as they are invalid anyway
for a parameter of type pointer-to-object. */
- if (DECL_P (expr) && DECL_TEMPLATE_PARM_P (expr))
+ if (value_dependent_expression_p (expr))
/* Non-type template parameters are OK. */
;
else if (cxx_dialect >= cxx11 && integer_zerop (expr))
@@ -6567,27 +6572,30 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
}
}
- if (!DECL_P (expr))
+ if (!value_dependent_expression_p (expr))
{
- if (complain & tf_error)
- error ("%qE is not a valid template argument for type %qT "
- "because it is not an object with linkage",
- expr, type);
- return NULL_TREE;
- }
+ if (!DECL_P (expr))
+ {
+ if (complain & tf_error)
+ error ("%qE is not a valid template argument for type %qT "
+ "because it is not an object with linkage",
+ expr, type);
+ return NULL_TREE;
+ }
- /* DR 1155 allows internal linkage in C++11 and up. */
- linkage_kind linkage = decl_linkage (expr);
- if (linkage < (cxx_dialect >= cxx11 ? lk_internal : lk_external))
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument for type %qT "
- "because object %qD does not have linkage",
- expr, type, expr);
- return NULL_TREE;
- }
+ /* DR 1155 allows internal linkage in C++11 and up. */
+ linkage_kind linkage = decl_linkage (expr);
+ if (linkage < (cxx_dialect >= cxx11 ? lk_internal : lk_external))
+ {
+ if (complain & tf_error)
+ error ("%qE is not a valid template argument for type %qT "
+ "because object %qD does not have linkage",
+ expr, type, expr);
+ return NULL_TREE;
+ }
- expr = build_nop (type, build_address (expr));
+ expr = build_nop (type, build_address (expr));
+ }
}
/* [temp.arg.nontype]/5, bullet 4
@@ -6611,7 +6619,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
/* Null pointer values are OK in C++11. */
return perform_qualification_conversions (type, expr);
- expr = convert_nontype_argument_function (type, expr, complain);
+ if (!value_dependent_expression_p (expr))
+ expr = convert_nontype_argument_function (type, expr, complain);
if (!expr || expr == error_mark_node)
return expr;
}
@@ -6635,7 +6644,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
return NULL_TREE;
}
- expr = convert_nontype_argument_function (type, expr, complain);
+ if (!value_dependent_expression_p (expr))
+ expr = convert_nontype_argument_function (type, expr, complain);
if (!expr || expr == error_mark_node)
return expr;
@@ -6655,7 +6665,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
/* [temp.arg.nontype] bullet 1 says the pointer to member
expression must be a pointer-to-member constant. */
- if (!check_valid_ptrmem_cst_expr (type, expr, complain))
+ if (!value_dependent_expression_p (expr)
+ && !check_valid_ptrmem_cst_expr (type, expr, complain))
return error_mark_node;
/* There is no way to disable standard conversions in
@@ -6690,7 +6701,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
{
/* [temp.arg.nontype] bullet 1 says the pointer to member
expression must be a pointer-to-member constant. */
- if (!check_valid_ptrmem_cst_expr (type, expr, complain))
+ if (!value_dependent_expression_p (expr)
+ && !check_valid_ptrmem_cst_expr (type, expr, complain))
return error_mark_node;
expr = perform_qualification_conversions (type, expr);
@@ -6993,6 +7005,22 @@ canonicalize_type_argument (tree arg, tsubst_flags_t complain)
return canon;
}
+/* And from inside dependent non-type arguments like sizeof(Type). */
+
+static tree
+canonicalize_expr_argument (tree arg, tsubst_flags_t complain)
+{
+ if (!arg || arg == error_mark_node)
+ return arg;
+ bool removed_attributes = false;
+ tree canon = strip_typedefs_expr (arg, &removed_attributes);
+ if (removed_attributes
+ && (complain & tf_warning))
+ warning (OPT_Wignored_attributes,
+ "ignoring attributes in template argument %qE", arg);
+ return canon;
+}
+
// A template declaration can be substituted for a constrained
// template template parameter only when the argument is more
// constrained than the parameter.
@@ -7278,7 +7306,7 @@ convert_template_argument (tree parm,
val = error_mark_node;
}
}
- else if (!dependent_template_arg_p (orig_arg)
+ else if (!type_dependent_expression_p (orig_arg)
&& !uses_template_parms (t))
/* We used to call digest_init here. However, digest_init
will report errors, which we don't want when complain
@@ -7292,10 +7320,7 @@ convert_template_argument (tree parm,
argument specification is valid. */
val = convert_nontype_argument (t, orig_arg, complain);
else
- {
- bool removed_attr = false;
- val = strip_typedefs_expr (orig_arg, &removed_attr);
- }
+ val = canonicalize_expr_argument (orig_arg, complain);
if (val == NULL_TREE)
val = error_mark_node;
@@ -13187,8 +13212,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return cp_build_qualified_type_real
(r, cp_type_quals (t) | cp_type_quals (r), complain);
}
+ else if (code == TEMPLATE_TEMPLATE_PARM)
+ return arg;
else
- /* TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX. */
+ /* TEMPLATE_PARM_INDEX. */
return convert_from_reference (unshare_expr (arg));
}
@@ -18225,6 +18252,9 @@ static bool uses_deducible_template_parms (tree type);
static bool
deducible_expression (tree expr)
{
+ /* Strip implicit conversions. */
+ while (CONVERT_EXPR_P (expr))
+ expr = TREE_OPERAND (expr, 0);
return (TREE_CODE (expr) == TEMPLATE_PARM_INDEX);
}
@@ -19567,7 +19597,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
But the only case I've seen it in so far has been array bounds, where
signedness is the only information lost, and I think that will be
okay. */
- while (TREE_CODE (parm) == NOP_EXPR)
+ while (CONVERT_EXPR_P (parm))
parm = TREE_OPERAND (parm, 0);
if (arg == error_mark_node)
@@ -20056,7 +20086,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
/* Types INTEGER_CST and MINUS_EXPR can come from array bounds. */
/* Type INTEGER_CST can come from ordinary constant template args. */
case INTEGER_CST:
- while (TREE_CODE (arg) == NOP_EXPR)
+ while (CONVERT_EXPR_P (arg))
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (arg) != INTEGER_CST)
diff --git a/gcc/testsuite/g++.dg/template/crash53.C b/gcc/testsuite/g++.dg/template/crash53.C
index a8d7c11..2a55943 100644
--- a/gcc/testsuite/g++.dg/template/crash53.C
+++ b/gcc/testsuite/g++.dg/template/crash53.C
@@ -5,7 +5,7 @@ template<int> struct A {};
template<typename T> struct B
{
- template<T I> B(A<I>); // { dg-error "template non-type parameter" }
+ template<T I> B(A<I>); // { dg-error "" }
};
B<double> a=A<0>(); // { dg-error "non-scalar type" }
diff --git a/gcc/testsuite/g++.dg/template/nontype28.C b/gcc/testsuite/g++.dg/template/nontype28.C
new file mode 100644
index 0000000..3d0d881
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/nontype28.C
@@ -0,0 +1,14 @@
+// PR c++/77656
+// { dg-do compile { target stdint_types } }
+
+#include <stdint.h>
+
+template<uint64_t _Val,
+ int _Val2 = (_Val >> 32)>
+class Test {};
+
+template<uint32_t _X>
+class Test2 : Test<_X> {};
+
+template<uint32_t _X>
+class Test3 : Test<(uint64_t) _X> {};
diff --git a/gcc/testsuite/g++.dg/template/nontype3.C b/gcc/testsuite/g++.dg/template/nontype3.C
index 1899ed0..2269e0f 100644
--- a/gcc/testsuite/g++.dg/template/nontype3.C
+++ b/gcc/testsuite/g++.dg/template/nontype3.C
@@ -16,7 +16,7 @@ template <int *PI>
void dep6(bar<PI+1> *); // { dg-error "" "integral or enumeration" }
template <int I>
-void dep7(bar<I+1> *);
+void dep7(bar<I+1> *); // { dg-error "" }
template <int *PI>
void dep8(foo< *PI > *); // { dg-error "" "integral or enumeration" }