c++: Correct the handling of alignof(expr) [PR88115]
authorPatrick Palka <ppalka@redhat.com>
Wed, 11 Nov 2020 19:43:39 +0000 (14:43 -0500)
committerPatrick Palka <ppalka@redhat.com>
Wed, 11 Nov 2020 19:43:38 +0000 (14:43 -0500)
We're currently neglecting to set the ALIGNOF_EXPR_STD_P flag on an
ALIGNOF_EXPR when its operand is an expression.  This leads to us
handling alignof(expr) as if it were written __alignof__(expr), and
returning the preferred alignment instead of the ABI alignment.  In the
testcase below, this causes the first and third static_assert to fail on
x86.

gcc/cp/ChangeLog:

PR c++/88115
* cp-tree.h (cxx_sizeof_or_alignof_expr): Add bool parameter.
* decl.c (fold_sizeof_expr): Pass false to
cxx_sizeof_or_alignof_expr.
* parser.c (cp_parser_unary_expression): Pass std_alignof to
cxx_sizeof_or_alignof_expr.
* pt.c (tsubst_copy): Pass false to cxx_sizeof_or_alignof_expr.
(tsubst_copy_and_build): Pass std_alignof to
cxx_sizeof_or_alignof_expr.
* typeck.c (cxx_alignof_expr): Add std_alignof bool parameter
and pass it to cxx_sizeof_or_alignof_type.  Set ALIGNOF_EXPR_STD_P
appropriately.
(cxx_sizeof_or_alignof_expr): Add std_alignof bool parameter
and pass it to cxx_alignof_expr.  Assert op is either
SIZEOF_EXPR or ALIGNOF_EXPR.

libcc1/ChangeLog:

PR c++/88115
* libcp1plugin.cc (plugin_build_unary_expr): Pass true to
cxx_sizeof_or_alignof_expr.

gcc/testsuite/ChangeLog:

PR c++/88115
* g++.dg/cpp0x/alignof6.C: New test.

gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/cpp0x/alignof6.C [new file with mode: 0644]
libcc1/libcp1plugin.cc

index 230a1525c637835fe1670f7bd08d0b25bc883828..63724c0e84f16bfbe7e8138273bac5250019d37e 100644 (file)
@@ -7461,7 +7461,7 @@ extern int comp_cv_qualification          (const_tree, const_tree);
 extern int comp_cv_qualification               (int, int);
 extern int comp_cv_qual_signature              (tree, tree);
 extern tree cxx_sizeof_or_alignof_expr         (location_t, tree,
-                                                enum tree_code, bool);
+                                                enum tree_code, bool, bool);
 extern tree cxx_sizeof_or_alignof_type         (location_t, tree,
                                                 enum tree_code, bool, bool);
 extern tree cxx_alignas_expr                    (tree);
index 42e704e7af295f077aee47eaa3e64778e7edbb49..c52111e329ce455a73caf4c687fac8153f972269 100644 (file)
@@ -10335,7 +10335,7 @@ fold_sizeof_expr (tree t)
   else
     r = cxx_sizeof_or_alignof_expr (EXPR_LOCATION (t),
                                    TREE_OPERAND (t, 0), SIZEOF_EXPR,
-                                   false);
+                                   false, false);
   if (r == error_mark_node)
     r = size_one_node;
   return r;
index 363228123108d0572a25fd8456b0fe97de6fa642..4f59fc48d0f1d1dd181afb76c0765163c8a83aa8 100644 (file)
@@ -8335,8 +8335,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
                           "ISO C++ does not allow %<alignof%> "
                           "with a non-type");
 
-               ret = cxx_sizeof_or_alignof_expr (compound_loc,
-                                                 operand, op, true);
+               ret = cxx_sizeof_or_alignof_expr (compound_loc, operand, op,
+                                                 std_alignof, true);
              }
            /* For SIZEOF_EXPR, just issue diagnostics, but keep
               SIZEOF_EXPR with the original operand.  */
index c592461c47415ab1d469a01c50692e3f4fcd8ee9..a932c2133e17d1db7b996a5ec51e44fae20637c9 100644 (file)
@@ -16790,6 +16790,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              else
                return cxx_sizeof_or_alignof_expr (input_location,
                                                   expanded, SIZEOF_EXPR,
+                                                  false,
                                                    complain & tf_error);
            }
          else
@@ -19732,7 +19733,7 @@ tsubst_copy_and_build (tree t,
                                          complain & tf_error);
        else
          r = cxx_sizeof_or_alignof_expr (input_location,
-                                         op1, TREE_CODE (t),
+                                         op1, TREE_CODE (t), std_alignof,
                                          complain & tf_error);
        if (TREE_CODE (t) == SIZEOF_EXPR && r != error_mark_node)
          {
index 08e0c80f9b021bb3ecd4bc4cb26baf7226ba337c..700e166ca6683d90c381c8e07f4079facb8edf93 100644 (file)
@@ -1832,10 +1832,12 @@ cxx_sizeof_expr (location_t loc, tree e, tsubst_flags_t complain)
 /* Implement the __alignof keyword: Return the minimum required
    alignment of E, measured in bytes.  For VAR_DECL's and
    FIELD_DECL's return DECL_ALIGN (which can be set from an
-   "aligned" __attribute__ specification).  */
+   "aligned" __attribute__ specification).  STD_ALIGNOF acts
+   like in cxx_sizeof_or_alignof_type.  */
 
 static tree
-cxx_alignof_expr (location_t loc, tree e, tsubst_flags_t complain)
+cxx_alignof_expr (location_t loc, tree e, bool std_alignof,
+                 tsubst_flags_t complain)
 {
   tree t;
 
@@ -1848,6 +1850,7 @@ cxx_alignof_expr (location_t loc, tree e, tsubst_flags_t complain)
       TREE_SIDE_EFFECTS (e) = 0;
       TREE_READONLY (e) = 1;
       SET_EXPR_LOCATION (e, loc);
+      ALIGNOF_EXPR_STD_P (e) = std_alignof;
 
       return e;
     }
@@ -1900,23 +1903,25 @@ cxx_alignof_expr (location_t loc, tree e, tsubst_flags_t complain)
     }
   else
     return cxx_sizeof_or_alignof_type (loc, TREE_TYPE (e),
-                                      ALIGNOF_EXPR, false,
+                                      ALIGNOF_EXPR, std_alignof,
                                        complain & tf_error);
 
   return fold_convert_loc (loc, size_type_node, t);
 }
 
 /* Process a sizeof or alignof expression E with code OP where the operand
-   is an expression.  */
+   is an expression. STD_ALIGNOF acts like in cxx_sizeof_or_alignof_type.  */
 
 tree
 cxx_sizeof_or_alignof_expr (location_t loc, tree e, enum tree_code op,
-                           bool complain)
+                           bool std_alignof, bool complain)
 {
+  gcc_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR);
   if (op == SIZEOF_EXPR)
     return cxx_sizeof_expr (loc, e, complain? tf_warning_or_error : tf_none);
   else
-    return cxx_alignof_expr (loc, e, complain? tf_warning_or_error : tf_none);
+    return cxx_alignof_expr (loc, e, std_alignof,
+                            complain? tf_warning_or_error : tf_none);
 }
 
 /*  Build a representation of an expression 'alignas(E).'  Return the
diff --git a/gcc/testsuite/g++.dg/cpp0x/alignof6.C b/gcc/testsuite/g++.dg/cpp0x/alignof6.C
new file mode 100644 (file)
index 0000000..b1a463d
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/88115
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-pedantic" }
+
+// Verify the non-standard extension alignof(expr) behaves like
+// alignof(type) to yield the ABI alignment of the type, and that
+// __alignof__(expr) behaves like __alignof__(type) to yield the
+// preferred alignment of the type.
+
+static_assert(alignof(double{}) == alignof(double), "");
+static_assert(__alignof__(double{}) == __alignof__(double), "");
+
+template <class T>
+void f() {
+  static_assert(alignof(T{}) == alignof(T), "");
+  static_assert(__alignof__(T{}) == __alignof__(T), "");
+}
+
+template void f<double>();
index 67a235f90953ddd23bde789219e35467ee78cb62..648368353cbf6ce04fc5bca85d7d2aae35ed2487 100644 (file)
@@ -2806,7 +2806,7 @@ plugin_build_unary_expr (cc1_plugin::connection *self,
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
       result = cxx_sizeof_or_alignof_expr (input_location,
-                                          op0, opcode, true);
+                                          op0, opcode, true, true);
       break;
 
     case DELETE_EXPR: