Commit 7d75ea04 by Jakub Jelinek

re PR c++/85437 (member pointer static upcast rejected in a constexpr context)

	PR c++/85437
	PR c++/49171
	* cp-tree.h (REINTERPRET_CAST_P): New.
	* constexpr.c (cxx_eval_constant_expression) <case NOP_EXPR>:
	Reject REINTERPET_CAST_P conversions.  Use cplus_expand_constant
	for non-trivial PTRMEM_CST cases.
	* typeck.c (build_nop_reinterpret): New.
	(build_reinterpret_cast_1): Use it.  Set REINTERPRET_CAST_P on
	NOP_EXPRs returned by cp_convert.

	* g++.dg/cpp0x/addressof1.C: Make reinterpret cases runtime checks.
	* g++.dg/cpp0x/constexpr-cast.C: Remove xfails
	* g++.dg/cpp0x/constexpr-nullptr-2.C: Likewise.
	* g++.dg/cpp0x/constexpr-pmf1.C: Check when optimized.
	* g++.dg/cpp0x/pr85437-1.C: New.
	* g++.dg/cpp0x/pr85437-2.C: New.
	* g++.dg/cpp0x/pr85437-3.C: New.
	* g++.dg/cpp0x/pr85437-4.C: New.

From-SVN: r259629
parent 90855339
2018-04-25 Nathan Sidwell <nathan@acm.org>
PR c++/85437
PR c++/49171
* cp-tree.h (REINTERPRET_CAST_P): New.
* constexpr.c (cxx_eval_constant_expression) <case NOP_EXPR>:
Reject REINTERPET_CAST_P conversions. Use cplus_expand_constant
for non-trivial PTRMEM_CST cases.
* typeck.c (build_nop_reinterpret): New.
(build_reinterpret_cast_1): Use it. Set REINTERPRET_CAST_P on
NOP_EXPRs returned by cp_convert.
2018-04-23 Jason Merrill <jason@redhat.com> 2018-04-23 Jason Merrill <jason@redhat.com>
PR c++/69560 - wrong alignof(double) on x86. PR c++/69560 - wrong alignof(double) on x86.
......
...@@ -1822,8 +1822,8 @@ reduced_constant_expression_p (tree t) ...@@ -1822,8 +1822,8 @@ reduced_constant_expression_p (tree t)
} }
/* Some expressions may have constant operands but are not constant /* Some expressions may have constant operands but are not constant
themselves, such as 1/0. Call this function (or rather, the macro themselves, such as 1/0. Call this function to check for that
following it) to check for that condition. condition.
We only call this in places that require an arithmetic constant, not in We only call this in places that require an arithmetic constant, not in
places where we might have a non-constant expression that can be a places where we might have a non-constant expression that can be a
...@@ -4579,9 +4579,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -4579,9 +4579,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
non_constant_p, overflow_p); non_constant_p, overflow_p);
break; break;
case NOP_EXPR:
if (REINTERPRET_CAST_P (t))
{
if (!ctx->quiet)
error_at (EXPR_LOC_OR_LOC (t, input_location),
"a reinterpret_cast is not a constant expression");
*non_constant_p = true;
return t;
}
/* FALLTHROUGH. */
case CONVERT_EXPR: case CONVERT_EXPR:
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
case NOP_EXPR:
case UNARY_PLUS_EXPR: case UNARY_PLUS_EXPR:
{ {
tree oldop = TREE_OPERAND (t, 0); tree oldop = TREE_OPERAND (t, 0);
...@@ -4595,20 +4604,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -4595,20 +4604,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (op) == PTRMEM_CST if (TREE_CODE (op) == PTRMEM_CST
&& !TYPE_PTRMEM_P (type)) && !TYPE_PTRMEM_P (type))
op = cplus_expand_constant (op); op = cplus_expand_constant (op);
if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR) if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR)
{ {
if (same_type_ignoring_top_level_qualifiers_p (type, if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (op))
TREE_TYPE (op)) && !can_convert_qual (type, op))
|| can_convert_qual (type, op)) op = cplus_expand_constant (op);
return cp_fold_convert (type, op); return cp_fold_convert (type, op);
else
{
if (!ctx->quiet)
error_at (EXPR_LOC_OR_LOC (t, input_location),
"a reinterpret_cast is not a constant expression");
*non_constant_p = true;
return t;
}
} }
if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST) if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
...@@ -4653,14 +4655,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -4653,14 +4655,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return t; return t;
} }
} }
if (op == oldop && tcode != UNARY_PLUS_EXPR) if (op == oldop && tcode != UNARY_PLUS_EXPR)
/* We didn't fold at the top so we could check for ptr-int /* We didn't fold at the top so we could check for ptr-int
conversion. */ conversion. */
return fold (t); return fold (t);
if (tcode == UNARY_PLUS_EXPR) if (tcode == UNARY_PLUS_EXPR)
r = fold_convert (TREE_TYPE (t), op); r = fold_convert (TREE_TYPE (t), op);
else else
r = fold_build1 (tcode, type, op); r = fold_build1 (tcode, type, op);
/* Conversion of an out-of-range value has implementation-defined /* Conversion of an out-of-range value has implementation-defined
behavior; the language considers it different from arithmetic behavior; the language considers it different from arithmetic
overflow, which is undefined. */ overflow, which is undefined. */
......
...@@ -372,6 +372,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ...@@ -372,6 +372,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM) TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM)
DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL) DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL)
SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT) SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT)
REINTERPRET_CAST_P (in NOP_EXPR)
ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR) ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR)
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG. TI_PENDING_TEMPLATE_FLAG.
...@@ -632,6 +633,11 @@ typedef struct ptrmem_cst * ptrmem_cst_t; ...@@ -632,6 +633,11 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
#define COND_EXPR_IS_VEC_DELETE(NODE) \ #define COND_EXPR_IS_VEC_DELETE(NODE) \
TREE_LANG_FLAG_0 (COND_EXPR_CHECK (NODE)) TREE_LANG_FLAG_0 (COND_EXPR_CHECK (NODE))
/* Nonzero if this NOP_EXPR is a reinterpret_cast. Such conversions
are not constexprs. Other NOP_EXPRs are. */
#define REINTERPRET_CAST_P(NODE) \
TREE_LANG_FLAG_0 (NOP_EXPR_CHECK (NODE))
/* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual /* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
sense of `same'. */ sense of `same'. */
#define same_type_p(TYPE1, TYPE2) \ #define same_type_p(TYPE1, TYPE2) \
......
...@@ -7280,6 +7280,18 @@ convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain) ...@@ -7280,6 +7280,18 @@ convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain)
return build_nop (type, expr); return build_nop (type, expr);
} }
/* Build a NOP_EXPR to TYPE, but mark it as a reinterpret_cast so that
constexpr evaluation knows to reject it. */
static tree
build_nop_reinterpret (tree type, tree expr)
{
tree ret = build_nop (type, expr);
if (ret != expr)
REINTERPRET_CAST_P (ret) = true;
return ret;
}
/* Return a representation for a reinterpret_cast from EXPR to TYPE. /* Return a representation for a reinterpret_cast from EXPR to TYPE.
If C_CAST_P is true, this reinterpret cast is being done as part of If C_CAST_P is true, this reinterpret cast is being done as part of
a C-style cast. If VALID_P is non-NULL, *VALID_P is set to a C-style cast. If VALID_P is non-NULL, *VALID_P is set to
...@@ -7414,7 +7426,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, ...@@ -7414,7 +7426,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
warning (OPT_Wcast_function_type, warning (OPT_Wcast_function_type,
"cast between incompatible function types" "cast between incompatible function types"
" from %qH to %qI", intype, type); " from %qH to %qI", intype, type);
return build_nop (type, expr); return build_nop_reinterpret (type, expr);
} }
else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)) else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
{ {
...@@ -7425,7 +7437,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, ...@@ -7425,7 +7437,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
warning (OPT_Wcast_function_type, warning (OPT_Wcast_function_type,
"cast between incompatible pointer to member types" "cast between incompatible pointer to member types"
" from %qH to %qI", intype, type); " from %qH to %qI", intype, type);
return build_nop (type, expr); return build_nop_reinterpret (type, expr);
} }
else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype)) else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype))) || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
...@@ -7451,7 +7463,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, ...@@ -7451,7 +7463,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
/* strict_aliasing_warning STRIP_NOPs its expr. */ /* strict_aliasing_warning STRIP_NOPs its expr. */
strict_aliasing_warning (EXPR_LOCATION (expr), type, expr); strict_aliasing_warning (EXPR_LOCATION (expr), type, expr);
return build_nop (type, expr); return build_nop_reinterpret (type, expr);
} }
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype)) else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type))) || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
...@@ -7462,7 +7474,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, ...@@ -7462,7 +7474,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
warning (OPT_Wconditionally_supported, warning (OPT_Wconditionally_supported,
"casting between pointer-to-function and pointer-to-object " "casting between pointer-to-function and pointer-to-object "
"is conditionally-supported"); "is conditionally-supported");
return build_nop (type, expr); return build_nop_reinterpret (type, expr);
} }
else if (VECTOR_TYPE_P (type)) else if (VECTOR_TYPE_P (type))
return convert_to_vector (type, expr); return convert_to_vector (type, expr);
...@@ -7478,7 +7490,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, ...@@ -7478,7 +7490,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
return error_mark_node; return error_mark_node;
} }
return cp_convert (type, expr, complain); expr = cp_convert (type, expr, complain);
if (TREE_CODE (expr) == NOP_EXPR)
/* Mark any nop_expr that created as a reintepret_cast. */
REINTERPRET_CAST_P (expr) = true;
return expr;
} }
tree tree
......
2018-04-25 Nathan Sidwell <nathan@acm.org>
Jakub Jelinek <jakub@redhat.com>
PR c++/85437
PR c++/49171
* g++.dg/cpp0x/addressof1.C: Make reinterpret cases runtime checks.
* g++.dg/cpp0x/constexpr-cast.C: Remove xfails
* g++.dg/cpp0x/constexpr-nullptr-2.C: Likewise.
* g++.dg/cpp0x/constexpr-pmf1.C: Check when optimized.
* g++.dg/cpp0x/pr85437-1.C: New.
* g++.dg/cpp0x/pr85437-2.C: New.
* g++.dg/cpp0x/pr85437-3.C: New.
* g++.dg/cpp0x/pr85437-4.C: New.
2018-04-24 Steven G. Kargl <kargl@gcc.gnu.org> 2018-04-24 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/85520 PR fortran/85520
...@@ -8,6 +22,7 @@ ...@@ -8,6 +22,7 @@
PR target/85512 PR target/85512
* gcc.dg/pr85512.c: New test. * gcc.dg/pr85512.c: New test.
2018-04-24 H.J. Lu <hongjiu.lu@intel.com>
PR target/85485 PR target/85485
* g++.dg/cet-notrack-1.C (dg-options): Remove -mcet. * g++.dg/cet-notrack-1.C (dg-options): Remove -mcet.
......
...@@ -18,9 +18,7 @@ static_assert (addressof (j) == &i, ""); ...@@ -18,9 +18,7 @@ static_assert (addressof (j) == &i, "");
struct S { int s; } s; struct S { int s; } s;
static_assert (__builtin_addressof (s) == &s, ""); static_assert (__builtin_addressof (s) == &s, "");
static_assert ((int *) __builtin_addressof (s) == &s.s, "");
static_assert (addressof (s) == &s, ""); static_assert (addressof (s) == &s, "");
static_assert ((int *) addressof (s) == &s.s, "");
struct T struct T
{ {
...@@ -31,9 +29,7 @@ struct T ...@@ -31,9 +29,7 @@ struct T
}; };
constexpr T t; constexpr T t;
T T::tt; T T::tt;
static_assert (__builtin_addressof (t) == (const T *) &t.p, "");
static_assert (&t == __builtin_addressof (T::tt), ""); static_assert (&t == __builtin_addressof (T::tt), "");
static_assert (addressof (t) == (const T *) &t.p, "");
static_assert (&t == addressof (T::tt), ""); static_assert (&t == addressof (T::tt), "");
struct S x, y; struct S x, y;
...@@ -76,8 +72,6 @@ constexpr int a = 1; ...@@ -76,8 +72,6 @@ constexpr int a = 1;
static_assert (__builtin_addressof (a) == &a, ""); static_assert (__builtin_addressof (a) == &a, "");
static_assert (addressof (a) == &a, ""); static_assert (addressof (a) == &a, "");
constexpr int c[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; constexpr int c[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
static_assert ((const int *) __builtin_addressof (c) == &c[0], "");
static_assert ((const int *) addressof (c) == &c[0], "");
void void
baz () baz ()
...@@ -93,4 +87,15 @@ main () ...@@ -93,4 +87,15 @@ main ()
|| __builtin_addressof (baz) != baz || __builtin_addressof (baz) != baz
|| addressof (baz) != baz) || addressof (baz) != baz)
__builtin_abort (); __builtin_abort ();
// reinterpret casts are not constexprs
if (! (((int *) __builtin_addressof (s) == &s.s)
&& ((int *) addressof (s) == &s.s)
&& (__builtin_addressof (t) == (const T *) &t.p)
&& (addressof (t) == (const T *) &t.p)
&& ((const int *) __builtin_addressof (c) == &c[0])
&& ((const int *) addressof (c) == &c[0])))
__builtin_abort ();
return 0;
} }
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
int i; int i;
// The following is accepted due to bug 49171. // The following was accepted due to bug 49171.
constexpr void *q = reinterpret_cast<void*>(&i); // { dg-error "" "bug c++/49171" { xfail *-*-* } } constexpr void *q = reinterpret_cast<void*>(&i); // { dg-error "not a constant expression" }
constexpr void *r0 = reinterpret_cast<void*>(1); // { dg-error "not a constant expression|reinterpret_cast from integer to pointer" } constexpr void *r0 = reinterpret_cast<void*>(1); // { dg-error "not a constant expression|reinterpret_cast from integer to pointer" }
constexpr void *r1 = reinterpret_cast<void*>(sizeof 'x'); // { dg-error ".reinterpret_cast<void\\*>\\(1\[ul\]\*\\). is not a constant expression" } constexpr void *r1 = reinterpret_cast<void*>(sizeof 'x'); // { dg-error ".reinterpret_cast<void\\*>\\(1\[ul\]\*\\). is not a constant expression" }
......
...@@ -99,9 +99,8 @@ constexpr const volatile void* pv3 = p0; ...@@ -99,9 +99,8 @@ constexpr const volatile void* pv3 = p0;
constexpr void* pv4 = static_cast<void*>(p0); constexpr void* pv4 = static_cast<void*>(p0);
constexpr const void* pv5 = static_cast<const void*>(p0); constexpr const void* pv5 = static_cast<const void*>(p0);
// The following should be rejected but isn't because of bug c++/49171 // The following was accepted due to bug c++/49171
// - [C++0x][constexpr] Constant expressions support reinterpret_cast constexpr void* pv6 = reinterpret_cast<void*>(p0); // { dg-error "not a constant expression" }
constexpr void* pv6 = reinterpret_cast<void*>(p0); // { dg-error "" "bug c++/49171" { xfail *-*-* } }
// Adding or subtracting zero from a null pointer is valid in C++. // Adding or subtracting zero from a null pointer is valid in C++.
constexpr int* p1 = p0 + 0; constexpr int* p1 = p0 + 0;
......
// PR c++/77775 // PR c++/77775
// { dg-options -fdump-tree-gimple } // { dg-options "-fdump-tree-fre1 -O1" }
// { dg-final { scan-tree-dump "== viewAdded" "gimple" { target c++11 } } } // { dg-final { scan-tree-dump "== viewAdded" "fre1" { target c++11 } } }
namespace Sublime { namespace Sublime {
struct View; struct View;
......
// PR c++/85437
// { dg-do compile { target c++11 } }
struct A { int a; constexpr A() : a(0) {} };
struct B : A { int x; constexpr B() : x(0) {} };
struct X { int z; constexpr X() : z(0) {} };
struct C : X, B {};
constexpr int C::*cbx = &B::x;
constexpr int B::*bx = &B::x;
constexpr int A::*abx = static_cast<int(A::*)>(&B::x); // { dg-bogus "not a constant expression" }
constexpr const C y;
constexpr const B& yb = y;
constexpr const A& ya = y;
constexpr int const *pcbx = &(y.*cbx);
constexpr int const *pbx = &(y.*bx);
constexpr int const *pabx = &(ya.*abx);
// PR c++/85437
// { dg-do compile { target c++11 } }
struct A { };
struct B : A { int x; };
constexpr int A::*abx
= reinterpret_cast<int(A::*)>(&B::x); // { dg-error "reinterpret.*constant" }
// PR c++/85437
// { dg-do compile { target c++11 } }
struct A { int y; };
struct B { int x; };
struct C : A, B {};
constexpr int C::*pci = &B::x;
constexpr int A::*pai = static_cast<int A::*>(static_cast<int C::*>(&B::x)); // { dg-bogus "not a constant expression" }
// PR c++/85437
// { dg-do compile { target c++11 } }
struct A { };
struct B { int x; };
struct C : A, B {};
constexpr int C::*pci = &B::x;
constexpr int A::*pai = static_cast<int A::*>(pci); // { dg-bogus "not a constant expression" }
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