aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/constexpr.c131
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/tree.c12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bit-cast11.C63
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bit-cast12.C68
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bit-cast13.C63
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bit-cast14.C75
7 files changed, 411 insertions, 2 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index b4b8a96..d851fae 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4275,6 +4275,118 @@ check_bit_cast_type (const constexpr_ctx *ctx, location_t loc, tree type,
return false;
}
+/* Helper function for cxx_eval_bit_cast. For unsigned char or
+ std::byte members of CONSTRUCTOR (recursively) if they contain
+ some indeterminate bits (as set in MASK), remove the ctor elts,
+ mark the CONSTRUCTOR as CONSTRUCTOR_NO_CLEARING and clear the
+ bits in MASK. */
+
+static void
+clear_uchar_or_std_byte_in_mask (location_t loc, tree t, unsigned char *mask)
+{
+ if (TREE_CODE (t) != CONSTRUCTOR)
+ return;
+
+ unsigned i, j = 0;
+ tree index, value;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, index, value)
+ {
+ tree type = TREE_TYPE (value);
+ if (TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE
+ && DECL_BIT_FIELD_TYPE (index) != NULL_TREE)
+ {
+ if (is_byte_access_type_not_plain_char (DECL_BIT_FIELD_TYPE (index)))
+ {
+ HOST_WIDE_INT fldsz = TYPE_PRECISION (TREE_TYPE (index));
+ gcc_assert (fldsz != 0);
+ HOST_WIDE_INT pos = int_byte_position (index);
+ HOST_WIDE_INT bpos
+ = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (index));
+ bpos %= BITS_PER_UNIT;
+ HOST_WIDE_INT end
+ = ROUND_UP (bpos + fldsz, BITS_PER_UNIT) / BITS_PER_UNIT;
+ gcc_assert (end == 1 || end == 2);
+ unsigned char *p = mask + pos;
+ unsigned char mask_save[2];
+ mask_save[0] = mask[pos];
+ mask_save[1] = end == 2 ? mask[pos + 1] : 0;
+ if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+ sorry_at (loc, "PDP11 bit-field handling unsupported"
+ " in %qs", "__builtin_bit_cast");
+ else if (BYTES_BIG_ENDIAN)
+ {
+ /* Big endian. */
+ if (bpos + fldsz <= BITS_PER_UNIT)
+ *p &= ~(((1 << fldsz) - 1)
+ << (BITS_PER_UNIT - bpos - fldsz));
+ else
+ {
+ gcc_assert (bpos);
+ *p &= ~(((1U << BITS_PER_UNIT) - 1) >> bpos);
+ p++;
+ fldsz -= BITS_PER_UNIT - bpos;
+ gcc_assert (fldsz && fldsz < BITS_PER_UNIT);
+ *p &= ((1U << BITS_PER_UNIT) - 1) >> fldsz;
+ }
+ }
+ else
+ {
+ /* Little endian. */
+ if (bpos + fldsz <= BITS_PER_UNIT)
+ *p &= ~(((1 << fldsz) - 1) << bpos);
+ else
+ {
+ gcc_assert (bpos);
+ *p &= ~(((1 << BITS_PER_UNIT) - 1) << bpos);
+ p++;
+ fldsz -= BITS_PER_UNIT - bpos;
+ gcc_assert (fldsz && fldsz < BITS_PER_UNIT);
+ *p &= ~((1 << fldsz) - 1);
+ }
+ }
+ if (mask_save[0] != mask[pos]
+ || (end == 2 && mask_save[1] != mask[pos + 1]))
+ {
+ CONSTRUCTOR_NO_CLEARING (t) = 1;
+ continue;
+ }
+ }
+ }
+ else if (is_byte_access_type_not_plain_char (type))
+ {
+ HOST_WIDE_INT pos;
+ if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+ pos = tree_to_shwi (index);
+ else
+ pos = int_byte_position (index);
+ if (mask[pos])
+ {
+ CONSTRUCTOR_NO_CLEARING (t) = 1;
+ mask[pos] = 0;
+ continue;
+ }
+ }
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ {
+ HOST_WIDE_INT pos;
+ if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+ pos = tree_to_shwi (index)
+ * tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))));
+ else
+ pos = int_byte_position (index);
+ clear_uchar_or_std_byte_in_mask (loc, value, mask + pos);
+ }
+ if (i != j)
+ {
+ CONSTRUCTOR_ELT (t, j)->index = index;
+ CONSTRUCTOR_ELT (t, j)->value = value;
+ }
+ ++j;
+ }
+ if (CONSTRUCTOR_NELTS (t) != j)
+ vec_safe_truncate (CONSTRUCTOR_ELTS (t), j);
+}
+
/* Subroutine of cxx_eval_constant_expression.
Attempt to evaluate a BIT_CAST_EXPR. */
@@ -4351,12 +4463,27 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
tree r = NULL_TREE;
if (can_native_interpret_type_p (TREE_TYPE (t)))
- r = native_interpret_expr (TREE_TYPE (t), ptr, len);
+ {
+ r = native_interpret_expr (TREE_TYPE (t), ptr, len);
+ if (is_byte_access_type_not_plain_char (TREE_TYPE (t)))
+ {
+ gcc_assert (len == 1);
+ if (mask[0])
+ {
+ memset (mask, 0, len);
+ r = build_constructor (TREE_TYPE (r), NULL);
+ CONSTRUCTOR_NO_CLEARING (r) = 1;
+ }
+ }
+ }
else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE)
{
r = native_interpret_aggregate (TREE_TYPE (t), ptr, 0, len);
if (r != NULL_TREE)
- clear_type_padding_in_mask (TREE_TYPE (t), mask);
+ {
+ clear_type_padding_in_mask (TREE_TYPE (t), mask);
+ clear_uchar_or_std_byte_in_mask (loc, r, mask);
+ }
}
if (r != NULL_TREE)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1ee2c57..3510512 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7791,6 +7791,7 @@ extern tree build_dummy_object (tree);
extern tree maybe_dummy_object (tree, tree *);
extern bool is_dummy_object (const_tree);
extern bool is_byte_access_type (tree);
+extern bool is_byte_access_type_not_plain_char (tree);
extern const struct attribute_spec cxx_attribute_table[];
extern tree make_ptrmem_cst (tree, tree);
extern tree cp_build_type_attribute_variant (tree, tree);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 1471ed8..52c5683 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4311,6 +4311,18 @@ is_byte_access_type (tree type)
&& !strcmp ("byte", TYPE_NAME_STRING (type)));
}
+/* Returns true if TYPE is unsigned char or std::byte. */
+
+bool
+is_byte_access_type_not_plain_char (tree type)
+{
+ type = TYPE_MAIN_VARIANT (type);
+ if (type == char_type_node)
+ return false;
+
+ return is_byte_access_type (type);
+}
+
/* Returns 1 iff type T is something we want to treat as a scalar type for
the purpose of deciding whether it is trivial/POD/standard-layout. */
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
new file mode 100644
index 0000000..a3eb31b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
@@ -0,0 +1,63 @@
+// P1272R4
+// { dg-do compile { target c++14 } }
+
+struct S { unsigned char a[2]; alignas(sizeof 0) int b; };
+struct T { char a; alignas(sizeof 0) int b; };
+struct U { char a : 1; char : 6; char b : 1; };
+struct V { int a; S b; };
+struct W { unsigned a; T b; };
+
+constexpr bool
+f1 ()
+{
+ T t = { 1, 2 };
+ S s = __builtin_bit_cast (S, t);
+ return s.a[0] == 1;
+}
+
+constexpr bool
+f2 ()
+{
+ U u = { 0, 0 };
+ unsigned char a = __builtin_bit_cast (unsigned char, u);
+ return true;
+}
+
+constexpr bool
+f3 ()
+{
+ T t = { 1, 2 };
+ S s = __builtin_bit_cast (S, t);
+ return s.a[1] == 0;
+}
+
+constexpr bool
+f4 ()
+{
+ U u = { 0, 0 };
+ unsigned char a = __builtin_bit_cast (unsigned char, u);
+ return a == 0; // { dg-error "is not a constant expression" }
+}
+
+constexpr bool
+f5 ()
+{
+ W t = { 1, 2 };
+ V s = __builtin_bit_cast (V, t);
+ return s.b.a[0] == 1;
+}
+
+constexpr bool
+f6 ()
+{
+ W t = { 1, 2 };
+ V s = __builtin_bit_cast (V, t);
+ return s.b.a[1] == 1;
+}
+
+constexpr bool a = f1 ();
+constexpr bool b = f2 ();
+constexpr bool c = f3 (); // { dg-error "accessing uninitialized array element" }
+constexpr bool d = f4 ();
+constexpr bool e = f5 ();
+constexpr bool f = f6 (); // { dg-error "accessing uninitialized array element" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
new file mode 100644
index 0000000..9c699dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
@@ -0,0 +1,68 @@
+// P1272R4
+// { dg-do compile { target c++14 } }
+
+namespace std
+{
+ enum class byte : unsigned char {};
+}
+
+struct S { unsigned char a[2]; alignas(sizeof 0) int b; };
+struct T { char a; alignas(sizeof 0) int b; };
+struct U { char a : 1; char : 6; char b : 1; };
+struct V { int a; S b; };
+struct W { unsigned a; T b; };
+
+constexpr bool
+f1 ()
+{
+ T t = { 1, 2 };
+ S s = __builtin_bit_cast (S, t);
+ return s.a[0] == 1;
+}
+
+constexpr bool
+f2 ()
+{
+ U u = { 0, 0 };
+ unsigned char a = __builtin_bit_cast (unsigned char, u);
+ return true;
+}
+
+constexpr bool
+f3 ()
+{
+ T t = { 1, 2 };
+ S s = __builtin_bit_cast (S, t);
+ return s.a[1] == 0;
+}
+
+constexpr bool
+f4 ()
+{
+ U u = { 0, 0 };
+ unsigned char a = __builtin_bit_cast (unsigned char, u);
+ return a == 0; // { dg-error "is not a constant expression" }
+}
+
+constexpr bool
+f5 ()
+{
+ W t = { 1, 2 };
+ V s = __builtin_bit_cast (V, t);
+ return s.b.a[0] == 1;
+}
+
+constexpr bool
+f6 ()
+{
+ W t = { 1, 2 };
+ V s = __builtin_bit_cast (V, t);
+ return s.b.a[1] == 1;
+}
+
+constexpr bool a = f1 ();
+constexpr bool b = f2 ();
+constexpr bool c = f3 (); // { dg-error "accessing uninitialized array element" }
+constexpr bool d = f4 ();
+constexpr bool e = f5 ();
+constexpr bool f = f6 (); // { dg-error "accessing uninitialized array element" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast13.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast13.C
new file mode 100644
index 0000000..f3bae59
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast13.C
@@ -0,0 +1,63 @@
+// P1272R4
+// { dg-do compile { target c++14 } }
+
+struct S { char a[2]; alignas(sizeof 0) int b; };
+struct T { char a; alignas(sizeof 0) int b; };
+struct U { char a : 1; char : 6; char b : 1; };
+struct V { int a; S b; };
+struct W { unsigned a; T b; };
+
+constexpr bool
+f1 ()
+{
+ T t = { 1, 2 };
+ S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized byte" }
+ return s.a[0] == 1;
+}
+
+constexpr bool
+f2 ()
+{
+ U u = { 0, 0 };
+ char a = __builtin_bit_cast (char, u); // { dg-error "accessing uninitialized byte" }
+ return true;
+}
+
+constexpr bool
+f3 ()
+{
+ T t = { 1, 2 };
+ S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized byte" }
+ return s.a[1] == 0;
+}
+
+constexpr bool
+f4 ()
+{
+ U u = { 0, 0 };
+ char a = __builtin_bit_cast (char, u); // { dg-error "accessing uninitialized byte" }
+ return a == 0;
+}
+
+constexpr bool
+f5 ()
+{
+ W t = { 1, 2 };
+ V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized byte" }
+ return s.b.a[0] == 1;
+}
+
+constexpr bool
+f6 ()
+{
+ W t = { 1, 2 };
+ V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized byte" }
+ return s.b.a[1] == 1;
+}
+
+constexpr bool a = f1 ();
+constexpr bool b = f2 ();
+constexpr bool c = f3 ();
+constexpr bool d = f4 ();
+constexpr bool e = f5 ();
+constexpr bool f = f6 ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
new file mode 100644
index 0000000..5e18591
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
@@ -0,0 +1,75 @@
+// P1272R4
+// { dg-do compile { target c++14 } }
+
+struct S { unsigned char a : 8, b : 5, c : 3, d, e; unsigned int f : 8, g : 24; };
+struct T1 { unsigned char a : 1, : 7, b : 5, c : 3, d, e; unsigned int f : 8, g : 24; };
+struct T2 { unsigned char a : 8, b : 1, : 4, c : 3, d, e; unsigned int f : 8, g : 24; };
+struct T3 { unsigned char a : 8, b : 5, c : 1, : 2, d, e; unsigned int f : 8, g : 24; };
+struct T4 { unsigned char a : 8, b : 5, c : 3, d, e; unsigned int f : 1, : 7, g : 24; };
+
+constexpr bool
+f1 ()
+{
+ T1 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t);
+ return true;
+}
+
+constexpr bool
+f2 ()
+{
+ T2 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t);
+ return true;
+}
+
+constexpr bool
+f3 ()
+{
+ T3 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t);
+ return true;
+}
+
+constexpr bool
+f4 ()
+{
+ T4 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized byte" }
+ return true;
+}
+
+constexpr bool
+f5 ()
+{
+ T1 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t);
+ unsigned char a = s.a;
+ return true;
+}
+
+constexpr bool
+f6 ()
+{
+ T2 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t);
+ unsigned char b = s.b;
+ return true;
+}
+
+constexpr bool
+f7 ()
+{
+ T3 t = { 0, 0, 0, 0, 0, 0, 0 };
+ S s = __builtin_bit_cast (S, t);
+ unsigned char c = s.c;
+ return true;
+}
+
+constexpr bool a = f1 ();
+constexpr bool b = f2 ();
+constexpr bool c = f3 ();
+constexpr bool d = f4 ();
+constexpr bool e = f5 (); // { dg-error "accessing uninitialized member" }
+constexpr bool f = f6 (); // { dg-error "accessing uninitialized member" }
+constexpr bool g = f7 (); // { dg-error "accessing uninitialized member" }