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
This commit is contained in:
Jakub Jelinek 2018-04-25 09:10:16 +02:00
parent 908553397a
commit 7d75ea04cf
13 changed files with 132 additions and 33 deletions

View File

@ -1,3 +1,15 @@
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.

View File

@ -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,
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,
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,
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. */

View File

@ -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;
#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) \

View File

@ -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,
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,
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,
/* 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,
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,
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

View File

@ -1,3 +1,17 @@
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 @@
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.

View File

@ -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
}; };
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;
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 ()
|| __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;
} }

View File

@ -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" }

View File

@ -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;

View File

@ -1,6 +1,6 @@
// 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;

View File

@ -0,0 +1,17 @@
// 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);

View File

@ -0,0 +1,8 @@
// 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" }

View File

@ -0,0 +1,8 @@
// 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" }

View File

@ -0,0 +1,8 @@
// 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" }