Hi!
I've backported following 25 patches from trunk to 9.x,
bootstrapped/regtested on x86_64-linux and i686-linux, committed
to gcc-9-branch.
Jakub
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-21 Jakub Jelinek <[email protected]>
Jason Merrill <[email protected]>
PR c++/90842
* parser.c (cp_parser_decl_specifier_seq): For concept or typedef
break early if CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR.
For type specifiers, set CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS
if CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR is set.
* g++.dg/cpp1y/lambda-generic-90842.C: New test.
--- gcc/cp/parser.c (revision 278537)
+++ gcc/cp/parser.c (revision 278538)
@@ -13998,6 +13998,10 @@ cp_parser_decl_specifier_seq (cp_parser*
case RID_CONCEPT:
ds = ds_concept;
cp_lexer_consume_token (parser->lexer);
+
+ if (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
+ break;
+
/* In C++20 a concept definition is just 'concept name = expr;'
Support that syntax by pretending we've seen 'bool'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
@@ -14025,6 +14029,10 @@ cp_parser_decl_specifier_seq (cp_parser*
ds = ds_typedef;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
+
+ if (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
+ break;
+
/* A constructor declarator cannot appear in a typedef. */
constructor_possible_p = false;
/* The "typedef" keyword can only occur in a declaration; we
@@ -14120,6 +14128,9 @@ cp_parser_decl_specifier_seq (cp_parser*
bool is_cv_qualifier;
tree type_spec;
+ if (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
+ flags |= CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS;
+
type_spec
= cp_parser_type_specifier (parser, flags,
decl_specs,
--- gcc/testsuite/g++.dg/cpp1y/lambda-generic-90842.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp1y/lambda-generic-90842.C (revision 278538)
@@ -0,0 +1,7 @@
+// PR c++/90842
+// { dg-do compile { target c++14 } }
+
+auto a = [](auto x) struct C { void foo (); } {}; // { dg-error
"expected" }
+ // { dg-error
"type-specifier invalid in lambda" "" { target *-*-* } .-1 }
+auto b = [](auto x) mutable typedef {}; // { dg-error
"'typedef' invalid in lambda" }
+auto d = [](auto x) mutable friend {}; // { dg-error "'friend'
invalid in lambda" }
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-22 Jakub Jelinek <[email protected]>
PR c/90677
* c-common.h (identifier_global_tag): Declare.
* c-format.c (get_pointer_to_named_type): Renamed to ...
(get_named_type): ... this. Use identifier_global_tag instead of
identifier_global_value, handle the return value being a TYPE_P.
(init_dynamic_diag_info): Adjust get_pointer_to_named_type callers
to call get_named_type instead. Formatting fixes.
* c-decl.c (identifier_global_tag): Define.
* cp-objcp-common.c (identifier_global_tag): Define.
* c-c++-common/pr90677.c: New test.
--- gcc/c-family/c-common.h (revision 278633)
+++ gcc/c-family/c-common.h (revision 278634)
@@ -800,6 +800,7 @@ extern void c_register_addr_space (const
extern bool in_late_binary_op;
extern const char *c_addr_space_name (addr_space_t as);
extern tree identifier_global_value (tree);
+extern tree identifier_global_tag (tree);
extern tree c_linkage_bindings (tree);
extern void record_builtin_type (enum rid, const char *, tree);
extern tree build_void_list_node (void);
--- gcc/c-family/c-format.c (revision 278633)
+++ gcc/c-family/c-format.c (revision 278634)
@@ -4899,31 +4899,32 @@ init_dynamic_gfc_info (void)
}
}
-/* Lookup the type named NAME and return a pointer-to-NAME type if found.
- Otherwise, return void_type_node if NAME has not been used yet, or
NULL_TREE if
- NAME is not a type (issuing an error). */
+/* Lookup the type named NAME and return a NAME type if found.
+ Otherwise, return void_type_node if NAME has not been used yet,
+ or NULL_TREE if NAME is not a type (issuing an error). */
static tree
-get_pointer_to_named_type (const char *name)
+get_named_type (const char *name)
{
- tree result;
- if ((result = maybe_get_identifier (name)))
+ if (tree result = maybe_get_identifier (name))
{
- result = identifier_global_value (result);
+ result = identifier_global_tag (result);
if (result)
{
- if (TREE_CODE (result) != TYPE_DECL)
+ if (TYPE_P (result))
+ ;
+ else if (TREE_CODE (result) == TYPE_DECL)
+ result = TREE_TYPE (result);
+ else
{
error ("%qs is not defined as a type", name);
result = NULL_TREE;
}
- else
- result = TREE_TYPE (result);
}
+ return result;
}
else
- result = void_type_node;
- return result;
+ return void_type_node;
}
/* Determine the types of "tree" and "location_t" in the code being
@@ -4953,23 +4954,24 @@ init_dynamic_diag_info (void)
an extra type level. */
if ((local_tree_type_node = maybe_get_identifier ("tree")))
{
- local_tree_type_node = identifier_global_value (local_tree_type_node);
+ local_tree_type_node
+ = identifier_global_value (local_tree_type_node);
if (local_tree_type_node)
{
if (TREE_CODE (local_tree_type_node) != TYPE_DECL)
{
error ("%<tree%> is not defined as a type");
- local_tree_type_node = 0;
+ local_tree_type_node = NULL_TREE;
}
else if (TREE_CODE (TREE_TYPE (local_tree_type_node))
!= POINTER_TYPE)
{
error ("%<tree%> is not defined as a pointer type");
- local_tree_type_node = 0;
+ local_tree_type_node = NULL_TREE;
}
else
- local_tree_type_node =
- TREE_TYPE (TREE_TYPE (local_tree_type_node));
+ local_tree_type_node
+ = TREE_TYPE (TREE_TYPE (local_tree_type_node));
}
}
else
@@ -4979,12 +4981,12 @@ init_dynamic_diag_info (void)
/* Similar to the above but for gimple*. */
if (!local_gimple_ptr_node
|| local_gimple_ptr_node == void_type_node)
- local_gimple_ptr_node = get_pointer_to_named_type ("gimple");
+ local_gimple_ptr_node = get_named_type ("gimple");
/* Similar to the above but for cgraph_node*. */
if (!local_cgraph_node_ptr_node
|| local_cgraph_node_ptr_node == void_type_node)
- local_cgraph_node_ptr_node = get_pointer_to_named_type ("cgraph_node");
+ local_cgraph_node_ptr_node = get_named_type ("cgraph_node");
static tree hwi;
--- gcc/c/c-decl.c (revision 278633)
+++ gcc/c/c-decl.c (revision 278634)
@@ -9941,6 +9941,20 @@ identifier_global_value (tree t)
return NULL_TREE;
}
+/* Return the global value of tag T as a symbol. */
+
+tree
+identifier_global_tag (tree t)
+{
+ struct c_binding *b;
+
+ for (b = I_TAG_BINDING (t); b; b = b->shadowed)
+ if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b))
+ return b->decl;
+
+ return NULL_TREE;
+}
+
/* In C, the only C-linkage public declaration is at file scope. */
tree
--- gcc/cp/cp-objcp-common.c (revision 278633)
+++ gcc/cp/cp-objcp-common.c (revision 278634)
@@ -352,6 +352,15 @@ identifier_global_value (tree name)
return get_global_binding (name);
}
+/* Similarly, but return struct/class/union NAME instead. */
+
+tree
+identifier_global_tag (tree name)
+{
+ return lookup_qualified_name (global_namespace, name, /*prefer_type*/2,
+ /*complain*/false);
+}
+
/* Register c++-specific dumps. */
void
--- gcc/testsuite/c-c++-common/pr90677.c (nonexistent)
+++ gcc/testsuite/c-c++-common/pr90677.c (revision 278634)
@@ -0,0 +1,11 @@
+/* PR c/90677 */
+/* { dg-do compile } */
+/* { dg-options "-W -Wall" } */
+
+struct cgraph_node;
+union tree_node;
+typedef union tree_node *tree;
+union gimple_statement_d;
+typedef union gimple_statement_d *gimple;
+struct cgraph_node *cgraph_node (tree);
+void foo (int, const char *, ...) __attribute__((__format__(__gcc_diag__, 2,
3)));
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-23 Jakub Jelinek <[email protected]>
PR target/92615
* config/i386/i386.c (ix86_md_asm_adjust): If dest_mode is
GET_MODE (dest), is not QImode, using ZERO_EXTEND and dest is not
register_operand, force x into register before storing it into dest.
Formatting fix.
* gcc.target/i386/pr92615.c: New test.
--- gcc/config/i386/i386.c (revision 278641)
+++ gcc/config/i386/i386.c (revision 278642)
@@ -20819,11 +20819,15 @@ ix86_md_asm_adjust (vec<rtx> &outputs, v
{
x = force_reg (dest_mode, const0_rtx);
- emit_insn (gen_movstrictqi
- (gen_lowpart (QImode, x), destqi));
+ emit_insn (gen_movstrictqi (gen_lowpart (QImode, x), destqi));
}
else
- x = gen_rtx_ZERO_EXTEND (dest_mode, destqi);
+ {
+ x = gen_rtx_ZERO_EXTEND (dest_mode, destqi);
+ if (dest_mode == GET_MODE (dest)
+ && !register_operand (dest, GET_MODE (dest)))
+ x = force_reg (dest_mode, x);
+ }
}
if (dest_mode != GET_MODE (dest))
--- gcc/testsuite/gcc.target/i386/pr92615.c (nonexistent)
+++ gcc/testsuite/gcc.target/i386/pr92615.c (revision 278642)
@@ -0,0 +1,45 @@
+/* PR target/92615 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+void *a;
+long long b;
+char c;
+
+void
+foo (void)
+{
+ void *p;
+ long long q;
+ char r;
+ __asm__ ("" : : "r" (&p), "r" (&q), "r" (&r));
+ __asm__ ("" : "=@cca" (p));
+ a = p;
+ __asm__ ("" : "=@cca" (q));
+ b = q;
+ __asm__ ("" : "=@cca" (r));
+ c = r;
+ __asm__ ("" : : "r" (&p), "r" (&q), "r" (&r));
+}
+
+void
+bar (void)
+{
+ void *p;
+ long long q;
+ char r;
+ __asm__ ("" : "=@cca" (p));
+ a = p;
+ __asm__ ("" : "=@cca" (q));
+ b = q;
+ __asm__ ("" : "=@cca" (r));
+ c = r;
+ __asm__ ("" : : "r" (p), "A" (q), "q" (r));
+}
+
+void
+baz (void)
+{
+ void *p = (void *) &p;
+ __asm__ __volatile__ ("" : "=@ccng" (p) : "r" (1));
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-26 Jakub Jelinek <[email protected]>
PR tree-optimization/92644
* tree-ssa-phiopt.c (minmax_replacement): Add INTEGRAL_TYPE_P check
next to INTEGER_CST checks.
* g++.dg/opt/pr92644.C: New test.
--- gcc/tree-ssa-phiopt.c (revision 278719)
+++ gcc/tree-ssa-phiopt.c (revision 278720)
@@ -1381,7 +1381,8 @@ minmax_replacement (basic_block cond_bb,
/* Turn EQ/NE of extreme values to order comparisons. */
if ((cmp == NE_EXPR || cmp == EQ_EXPR)
- && TREE_CODE (rhs) == INTEGER_CST)
+ && TREE_CODE (rhs) == INTEGER_CST
+ && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
{
if (wi::eq_p (wi::to_wide (rhs), wi::min_value (TREE_TYPE (rhs))))
{
@@ -1407,7 +1408,8 @@ minmax_replacement (basic_block cond_bb,
larger = rhs;
/* If we have smaller < CST it is equivalent to smaller <= CST-1.
Likewise smaller <= CST is equivalent to smaller < CST+1. */
- if (TREE_CODE (larger) == INTEGER_CST)
+ if (TREE_CODE (larger) == INTEGER_CST
+ && INTEGRAL_TYPE_P (TREE_TYPE (larger)))
{
if (cmp == LT_EXPR)
{
@@ -1435,7 +1437,8 @@ minmax_replacement (basic_block cond_bb,
larger = gimple_cond_lhs (cond);
/* If we have larger > CST it is equivalent to larger >= CST+1.
Likewise larger >= CST is equivalent to larger > CST-1. */
- if (TREE_CODE (smaller) == INTEGER_CST)
+ if (TREE_CODE (smaller) == INTEGER_CST
+ && INTEGRAL_TYPE_P (TREE_TYPE (smaller)))
{
wi::overflow_type overflow;
if (cmp == GT_EXPR)
--- gcc/testsuite/g++.dg/opt/pr92644.C (nonexistent)
+++ gcc/testsuite/g++.dg/opt/pr92644.C (revision 278720)
@@ -0,0 +1,6 @@
+// PR tree-optimization/92644
+// { dg-do compile { target c++14 } }
+// { dg-options "-O2 -fno-early-inlining" }
+
+inline auto foo () { return nullptr; }
+int bar () { return foo () ? 1 : 0; }
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-26 Jakub Jelinek <[email protected]>
PR sanitizer/92154
* sanitizer_common/sanitizer_platform_limits_posix.h: Cherry-pick
llvm-project revision 947f9692440836dcb8d88b74b69dd379d85974ce.
* sanitizer_common/sanitizer_platform_limits_posix.cc: Likewise.
--- libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
(revision 278721)
+++ libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
(revision 278722)
@@ -211,26 +211,13 @@ namespace __sanitizer {
u64 __unused1;
u64 __unused2;
#elif defined(__sparc__)
-#if defined(__arch64__)
unsigned mode;
- unsigned short __pad1;
-#else
- unsigned short __pad1;
- unsigned short mode;
unsigned short __pad2;
-#endif
unsigned short __seq;
unsigned long long __unused1;
unsigned long long __unused2;
-#elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__)
- unsigned int mode;
- unsigned short __seq;
- unsigned short __pad1;
- unsigned long __unused1;
- unsigned long __unused2;
#else
- unsigned short mode;
- unsigned short __pad1;
+ unsigned int mode;
unsigned short __seq;
unsigned short __pad2;
#if defined(__x86_64__) && !defined(_LP64)
--- libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
(revision 278721)
+++ libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
(revision 278722)
@@ -1156,12 +1156,9 @@ CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
-#if (!defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21)) && \
- !defined(__arm__)
-/* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */
-/* On Arm glibc 2.31 and later provide a different mode field, this field is
- never used by libsanitizer so we can simply ignore this assert for all glibc
- versions. */
+#if !SANITIZER_LINUX || __GLIBC_PREREQ (2, 31)
+/* glibc 2.30 and earlier provided 16-bit mode field instead of 32-bit
+ on many architectures. */
CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
#endif
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-26 Jakub Jelinek <[email protected]>
PR c++/61414
* c-attribs.c (handle_mode_attribute): Add mode attribute to
ENUMERAL_TYPEs.
* class.c (enum_to_min_precision): New hash_map.
(enum_min_precision): New function.
(check_bitfield_decl): Use it.
* g++.dg/cpp0x/enum23.C: Remove xfail.
* g++.dg/cpp0x/enum28.C: New test.
--- gcc/c-family/c-attribs.c (revision 278735)
+++ gcc/c-family/c-attribs.c (revision 278736)
@@ -1866,6 +1866,7 @@ handle_mode_attribute (tree *node, tree
typefm = make_signed_type (TYPE_PRECISION (typefm));
TREE_TYPE (typefm) = type;
}
+ *no_add_attrs = false;
}
else if (VECTOR_MODE_P (mode)
? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm))
--- gcc/cp/class.c (revision 278735)
+++ gcc/cp/class.c (revision 278736)
@@ -3265,6 +3265,60 @@ add_implicitly_declared_members (tree t,
}
}
+/* Cache of enum_min_precision values. */
+static GTY((deletable)) hash_map<tree, int> *enum_to_min_precision;
+
+/* Return the minimum precision of a bit-field needed to store all
+ enumerators of ENUMERAL_TYPE TYPE. */
+
+static int
+enum_min_precision (tree type)
+{
+ type = TYPE_MAIN_VARIANT (type);
+ /* For unscoped enums without fixed underlying type and without mode
+ attribute we can just use precision of the underlying type. */
+ if (UNSCOPED_ENUM_P (type)
+ && !ENUM_FIXED_UNDERLYING_TYPE_P (type)
+ && !lookup_attribute ("mode", TYPE_ATTRIBUTES (type)))
+ return TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type));
+
+ if (enum_to_min_precision == NULL)
+ enum_to_min_precision = hash_map<tree, int>::create_ggc (37);
+
+ bool existed;
+ int prec = enum_to_min_precision->get_or_insert (type, &existed);
+ if (existed)
+ return prec;
+
+ tree minnode, maxnode;
+ if (TYPE_VALUES (type))
+ {
+ minnode = maxnode = NULL_TREE;
+ for (tree values = TYPE_VALUES (type);
+ values; values = TREE_CHAIN (values))
+ {
+ tree decl = TREE_VALUE (values);
+ tree value = DECL_INITIAL (decl);
+ if (value == error_mark_node)
+ value = integer_zero_node;
+ if (!minnode)
+ minnode = maxnode = value;
+ else if (tree_int_cst_lt (maxnode, value))
+ maxnode = value;
+ else if (tree_int_cst_lt (value, minnode))
+ minnode = value;
+ }
+ }
+ else
+ minnode = maxnode = integer_zero_node;
+
+ signop sgn = tree_int_cst_sgn (minnode) >= 0 ? UNSIGNED : SIGNED;
+ int lowprec = tree_int_cst_min_precision (minnode, sgn);
+ int highprec = tree_int_cst_min_precision (maxnode, sgn);
+ prec = MAX (lowprec, highprec);
+ return prec;
+}
+
/* FIELD is a bit-field. We are finishing the processing for its
enclosing type. Issue any appropriate messages and set appropriate
flags. Returns false if an error has been diagnosed. */
@@ -3326,7 +3380,7 @@ check_bitfield_decl (tree field)
"width of %qD exceeds its type", field);
else if (TREE_CODE (type) == ENUMERAL_TYPE)
{
- int prec = TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type));
+ int prec = enum_min_precision (type);
if (compare_tree_int (w, prec) < 0)
warning_at (DECL_SOURCE_LOCATION (field), 0,
"%qD is too small to hold all values of %q#T",
--- gcc/testsuite/g++.dg/cpp0x/enum23.C (revision 278735)
+++ gcc/testsuite/g++.dg/cpp0x/enum23.C (revision 278736)
@@ -5,5 +5,5 @@ enum class MyEnum { A = 1 };
struct MyClass
{
- MyEnum Field1 : 3; // { dg-bogus "warning: 'MyClass::Field1' is too small"
"" { xfail *-*-* } }
+ MyEnum Field1 : 3; // { dg-bogus "warning: 'MyClass::Field1' is too small" }
};
--- gcc/testsuite/g++.dg/cpp0x/enum38.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp0x/enum38.C (revision 278736)
@@ -0,0 +1,25 @@
+// PR c++/61414
+// { dg-do compile { target c++11 } }
+
+enum C { C0 = -4, C1 = 3 };
+enum D { D0 = 0, D1 = 15 };
+enum class E { E0 = -4, E1 = 3 };
+enum F : unsigned { F0 = 0, F1 = 15 };
+enum __attribute__((__mode__ (__QI__))) G { G0 = -4, G1 = 3 };
+enum __attribute__((__mode__ (__HI__))) H { H0 = 0, H1 = 15 };
+
+struct S
+{
+ C a : 2; // { dg-warning "'S::a' is too small to hold all values of
'enum C'" }
+ C b : 3; // { dg-bogus "'S::b' is too small to hold all values of 'enum
C'" }
+ D c : 3; // { dg-warning "'S::c' is too small to hold all values of
'enum D'" }
+ D d : 4; // { dg-bogus "'S::d' is too small to hold all values of 'enum
D'" }
+ E e : 2; // { dg-warning "'S::e' is too small to hold all values of
'enum class E'" }
+ E f : 3; // { dg-bogus "'S::f' is too small to hold all values of 'enum
class E'" }
+ F g : 3; // { dg-warning "'S::g' is too small to hold all values of
'enum F'" }
+ F h : 4; // { dg-bogus "'S::h' is too small to hold all values of 'enum
F'" }
+ G i : 2; // { dg-warning "'S::i' is too small to hold all values of
'enum G'" }
+ G j : 3; // { dg-bogus "'S::j' is too small to hold all values of 'enum
G'" }
+ H k : 3; // { dg-warning "'S::k' is too small to hold all values of
'enum H'" }
+ H l : 4; // { dg-bogus "'S::l' is too small to hold all values of 'enum
H'" }
+};
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-26 Jakub Jelinek <[email protected]>
PR c++/92648
* parser.c (cp_parser_std_attribute): For unknown attributes,
skip balanced token seq instead of trying to parse
attribute-argument-clause as expression list.
* g++.dg/cpp0x/gen-attrs-71.C: New test.
--- gcc/cp/parser.c (revision 278736)
+++ gcc/cp/parser.c (revision 278737)
@@ -2650,6 +2650,7 @@ static bool cp_parser_init_statement_p
(cp_parser *);
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
+static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
/* Concept-related syntactic transformations */
@@ -26189,6 +26190,17 @@ cp_parser_std_attribute (cp_parser *pars
/* A GNU attribute that takes an identifier in parameter. */
attr_flag = id_attr;
+ const attribute_spec *as
+ = lookup_attribute_spec (TREE_PURPOSE (attribute));
+ if (as == NULL)
+ {
+ /* For unknown attributes, just skip balanced tokens instead of
+ trying to parse the arguments. */
+ for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n)
+ cp_lexer_consume_token (parser->lexer);
+ return attribute;
+ }
+
vec = cp_parser_parenthesized_expression_list
(parser, attr_flag, /*cast_p=*/false,
/*allow_expansion_p=*/true,
--- gcc/testsuite/g++.dg/cpp0x/gen-attrs-71.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-71.C (revision 278737)
@@ -0,0 +1,7 @@
+// PR c++/92648
+// { dg-do compile { target c++11 } }
+
+int a [[gnu::no_such_attribute(![!(!)!]!,;;)]]; // { dg-warning
"ignored" }
+int b [[no_such_namespace::nonexisting_attribute(linear(c, d : 2),
reduction(*:e), linear(uval (f)))]]; // { dg-warning "ignored" }
+int c [[gnu::nonexisting_attribute()]]; // { dg-warning "ignored" }
+int d [[gnu::another_nonexistent_attr(1,"abcd",g+6)]]; // { dg-warning
"ignored" }
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-27 Jakub Jelinek <[email protected]>
PR debug/92664
* dwarf2out.c (lookup_filename): Use "<stdin>" instead of "".
--- gcc/dwarf2out.c (revision 278751)
+++ gcc/dwarf2out.c (revision 278752)
@@ -27118,6 +27118,9 @@ lookup_filename (const char *file_name)
if (!file_name)
return NULL;
+ if (!file_name[0])
+ file_name = "<stdin>";
+
dwarf_file_data **slot
= file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
INSERT);
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-27 Jakub Jelinek <[email protected]>
PR c++/92524
* tree.c (replace_placeholders_r): Don't walk constructor elts with
RANGE_EXPR indexes.
* g++.dg/cpp0x/pr92524.C: New test.
--- gcc/cp/tree.c (revision 278758)
+++ gcc/cp/tree.c (revision 278759)
@@ -3144,6 +3144,11 @@ replace_placeholders_r (tree* t, int* wa
tree type = TREE_TYPE (*valp);
tree subob = obj;
+ /* Elements with RANGE_EXPR index shouldn't have any
+ placeholders in them. */
+ if (ce->index && TREE_CODE (ce->index) == RANGE_EXPR)
+ continue;
+
if (TREE_CODE (*valp) == CONSTRUCTOR
&& AGGREGATE_TYPE_P (type))
{
--- gcc/testsuite/g++.dg/cpp0x/pr92524.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp0x/pr92524.C (revision 278759)
@@ -0,0 +1,12 @@
+// PR c++/92524
+// { dg-do compile { target c++11 } }
+
+struct A { char a = '*'; };
+struct B { A b[64]; };
+
+void
+foo ()
+{
+ A a;
+ B{a};
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-27 Jakub Jelinek <[email protected]>
PR fortran/91944
* simplify.c (gfc_simplify_spread): Check gfc_init_expr_flag instead
of gfc_current_ns->sym_root->n.sym->attr.flavor == FL_PARAMETER.
* gfortran.dg/spread_size_limit_2.f90: New test.
--- gcc/fortran/simplify.c (revision 278761)
+++ gcc/fortran/simplify.c (revision 278762)
@@ -7656,7 +7656,7 @@ gfc_simplify_spread (gfc_expr *source, g
nelem = mpz_get_si (size) * ncopies;
if (nelem > flag_max_array_constructor)
{
- if (gfc_current_ns->sym_root->n.sym->attr.flavor == FL_PARAMETER)
+ if (gfc_init_expr_flag)
{
gfc_error ("The number of elements (%d) in the array constructor "
"at %L requires an increase of the allowed %d upper "
--- gcc/testsuite/gfortran.dg/spread_size_limit_2.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/spread_size_limit_2.f90 (revision 278762)
@@ -0,0 +1,11 @@
+! PR fortran/91944
+! { dg-do compile }
+! { dg-options "-fmax-array-constructor=65535" }
+
+program pr91944
+ integer, parameter :: n = 10
+ integer, parameter :: m = 65536
+ integer :: i
+ integer :: x(n,m) = spread([(i,i=1,n)], dim=2, ncopies=m) ! { dg-error
"requires an increase of the allowed 65535 upper limit" }
+ print *, x(n,m)
+end
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-28 Jakub Jelinek <[email protected]>
PR c++/92695
* decl2.c (mark_used): Don't call note_vague_linkage_fn for pure
virtual functions, even if they are declared inline.
* g++.dg/warn/inline3.C: New test.
--- gcc/cp/decl2.c (revision 278801)
+++ gcc/cp/decl2.c (revision 278802)
@@ -5596,8 +5596,11 @@ mark_used (tree decl, tsubst_flags_t com
vec_safe_push (no_linkage_decls, decl);
}
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
- && !DECL_INITIAL (decl) && !DECL_ARTIFICIAL (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (decl)
+ && !DECL_INITIAL (decl)
+ && !DECL_ARTIFICIAL (decl)
+ && !DECL_PURE_VIRTUAL_P (decl))
/* Remember it, so we can check it was defined. */
note_vague_linkage_fn (decl);
--- gcc/testsuite/g++.dg/warn/inline3.C (nonexistent)
+++ gcc/testsuite/g++.dg/warn/inline3.C (revision 278802)
@@ -0,0 +1,20 @@
+struct S {
+ inline virtual void foo () = 0; // { dg-bogus "used but never defined" }
+#if __cplusplus > 201703L
+ constexpr virtual void bar () = 0; // { dg-bogus "used but never defined"
"" { target c++2a } }
+#else
+ inline virtual void bar () = 0; // { dg-bogus "used but never defined"
"" { target c++17_down } }
+#endif
+ S () {}
+};
+struct T : public S {
+ inline virtual void foo () {}
+#if __cplusplus > 201703L
+ constexpr virtual void bar () {}
+#else
+ inline virtual void bar () {}
+#endif
+ T () {}
+};
+T t;
+void foo (S *s) { s->foo (); s->bar (); }
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-11-29 Jakub Jelinek <[email protected]>
PR c++/60228
* parser.c (cp_parser_omp_declare_reduction_exprs): If
processing_template_decl, wrap the combiner or initializer
into EXPR_STMT.
* decl.c (start_preparsed_function): Don't start a lambda scope
for DECL_OMP_DECLARE_REDUCTION_P functions.
(finish_function): Don't finish a lambda scope for
DECL_OMP_DECLARE_REDUCTION_P functions, nor cp_fold_function
them nor cp_genericize them.
* mangle.c (decl_mangling_context): Look through
DECL_OMP_DECLARE_REDUCTION_P functions.
* semantics.c (expand_or_defer_fn_1): For DECL_OMP_DECLARE_REDUCTION_P
functions, use tentative linkage, don't keep their bodies with
-fkeep-inline-functions and return false at the end.
* g++.dg/gomp/openmp-simd-2.C: Don't expect bodies for
DECL_OMP_DECLARE_REDUCTION_P functions.
* testsuite/libgomp.c++/udr-20.C: New test.
* testsuite/libgomp.c++/udr-21.C: New test.
--- gcc/cp/decl.c (revision 278830)
+++ gcc/cp/decl.c (revision 278831)
@@ -15632,7 +15632,8 @@ start_preparsed_function (tree decl1, tr
&& !implicit_default_ctor_p (decl1))
cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr);
- start_lambda_scope (decl1);
+ if (!DECL_OMP_DECLARE_REDUCTION_P (decl1))
+ start_lambda_scope (decl1);
return true;
}
@@ -16040,7 +16041,8 @@ finish_function (bool inline_p)
if (fndecl == NULL_TREE)
return error_mark_node;
- finish_lambda_scope ();
+ if (!DECL_OMP_DECLARE_REDUCTION_P (fndecl))
+ finish_lambda_scope ();
if (c_dialect_objc ())
objc_finish_function ();
@@ -16157,7 +16159,7 @@ finish_function (bool inline_p)
invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
/* Perform delayed folding before NRV transformation. */
- if (!processing_template_decl)
+ if (!processing_template_decl && !DECL_OMP_DECLARE_REDUCTION_P (fndecl))
cp_fold_function (fndecl);
/* Set up the named return value optimization, if we can. Candidate
@@ -16280,7 +16282,8 @@ finish_function (bool inline_p)
if (!processing_template_decl)
{
struct language_function *f = DECL_SAVED_FUNCTION_DATA (fndecl);
- cp_genericize (fndecl);
+ if (!DECL_OMP_DECLARE_REDUCTION_P (fndecl))
+ cp_genericize (fndecl);
/* Clear out the bits we don't need. */
f->x_current_class_ptr = NULL;
f->x_current_class_ref = NULL;
--- gcc/cp/semantics.c (revision 278830)
+++ gcc/cp/semantics.c (revision 278831)
@@ -4417,7 +4417,7 @@ expand_or_defer_fn_1 (tree fn)
if (DECL_INTERFACE_KNOWN (fn))
/* We've already made a decision as to how this function will
be handled. */;
- else if (!at_eof)
+ else if (!at_eof || DECL_OMP_DECLARE_REDUCTION_P (fn))
tentative_decl_linkage (fn);
else
import_export_decl (fn);
@@ -4429,5 +4431,6 @@ expand_or_defer_fn_1 (tree fn)
if (DECL_DECLARED_INLINE_P (fn)
&& !DECL_REALLY_EXTERN (fn)
+ && !DECL_OMP_DECLARE_REDUCTION_P (fn)
&& (flag_keep_inline_functions
|| (flag_keep_inline_dllexport
&& lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))))
@@ -4461,6 +4464,9 @@ expand_or_defer_fn_1 (tree fn)
return false;
}
+ if (DECL_OMP_DECLARE_REDUCTION_P (fn))
+ return false;
+
return true;
}
--- gcc/cp/parser.c (revision 278830)
+++ gcc/cp/parser.c (revision 278831)
@@ -41244,6 +41244,8 @@ cp_parser_omp_declare_reduction_exprs (t
combiner = cp_parser_expression (parser);
finish_expr_stmt (combiner);
block = finish_omp_structured_block (block);
+ if (processing_template_decl)
+ block = build_stmt (input_location, EXPR_STMT, block);
add_stmt (block);
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
@@ -41348,6 +41350,8 @@ cp_parser_omp_declare_reduction_exprs (t
block = finish_omp_structured_block (block);
cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL);
+ if (processing_template_decl)
+ block = build_stmt (input_location, EXPR_STMT, block);
add_stmt (block);
if (ctor)
--- gcc/cp/mangle.c (revision 278830)
+++ gcc/cp/mangle.c (revision 278831)
@@ -873,7 +873,16 @@ decl_mangling_context (tree decl)
else if (template_type_parameter_p (decl))
/* template type parms have no mangling context. */
return NULL_TREE;
- return CP_DECL_CONTEXT (decl);
+
+ tcontext = CP_DECL_CONTEXT (decl);
+
+ /* Ignore the artificial declare reduction functions. */
+ if (tcontext
+ && TREE_CODE (tcontext) == FUNCTION_DECL
+ && DECL_OMP_DECLARE_REDUCTION_P (tcontext))
+ return decl_mangling_context (tcontext);
+
+ return tcontext;
}
/* <name> ::= <unscoped-name>
--- gcc/testsuite/g++.dg/gomp/openmp-simd-2.C (revision 278830)
+++ gcc/testsuite/g++.dg/gomp/openmp-simd-2.C (revision 278831)
@@ -36,8 +36,6 @@ void bar(int n, float *a, float *b)
a[i] = b[i];
}
-/* { dg-final { scan-tree-dump-times "Function void omp declare reduction
operator\\+" 1 "original" } } */
-/* { dg-final { scan-tree-dump-times "Function void omp declare reduction foo"
2 "original" } } */
/* { dg-final { scan-tree-dump-times "pragma omp simd reduction\\(u\\)
reduction\\(t\\) reduction\\(\\+:s\\) aligned\\(a:32\\)" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "pragma omp simd safelen\\(64\\)" 1
"original" } } */
/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */
--- libgomp/testsuite/libgomp.c++/udr-20.C (nonexistent)
+++ libgomp/testsuite/libgomp.c++/udr-20.C (revision 278832)
@@ -0,0 +1,54 @@
+// PR c++/60228
+// { dg-additional-options "-std=c++11" }
+
+extern "C" void abort ();
+
+struct A
+{
+ typedef int T;
+ #pragma omp declare reduction (x : T : omp_out += omp_in + [](){ return 0;
}()) initializer (omp_priv = [](){ return 0; }())
+ static void foo ();
+};
+
+template <typename T>
+struct B
+{
+ #pragma omp declare reduction (x : T : omp_out += omp_in + [](){ return T
(0); }()) initializer (omp_priv = [](){ return T (0); }())
+ static void foo ();
+};
+
+void
+A::foo ()
+{
+ int r = 0, s = 0;
+ #pragma omp parallel for reduction (x : r, s)
+ for (int i = 0; i < 64; i++)
+ {
+ r++;
+ s += i;
+ }
+ if (r != 64 || s != (64 * 63) / 2)
+ abort ();
+}
+
+template <typename T>
+void
+B<T>::foo ()
+{
+ T r = 0, s = 0;
+ #pragma omp parallel for reduction (x : r, s)
+ for (int i = 0; i < 64; i++)
+ {
+ r++;
+ s += i;
+ }
+ if (r != 64 || s != (64 * 63) / 2)
+ abort ();
+}
+
+int
+main ()
+{
+ A::foo ();
+ B<long>::foo ();
+}
--- libgomp/testsuite/libgomp.c++/udr-21.C (nonexistent)
+++ libgomp/testsuite/libgomp.c++/udr-21.C (revision 278832)
@@ -0,0 +1,54 @@
+// PR c++/60228
+// { dg-additional-options "-std=c++11" }
+
+extern "C" void abort ();
+
+struct A
+{
+ typedef int T;
+ #pragma omp declare reduction (y : T : [&omp_out, &omp_in]() { omp_out +=
omp_in; return 0; }()) initializer (omp_priv = [omp_orig]() { return omp_orig;
}())
+ static void foo ();
+};
+
+template <typename T>
+struct B
+{
+ #pragma omp declare reduction (y : T : [&omp_out, &omp_in]() { omp_out +=
omp_in; return 0; }()) initializer (omp_priv = [omp_orig]() { return omp_orig;
}())
+ static void foo ();
+};
+
+void
+A::foo ()
+{
+ int r = 0, s = 0;
+ #pragma omp parallel for reduction (y : r, s)
+ for (int i = 0; i < 64; i++)
+ {
+ r++;
+ s += i;
+ }
+ if (r != 64 || s != (64 * 63) / 2)
+ abort ();
+}
+
+template <typename T>
+void
+B<T>::foo ()
+{
+ T r = 0, s = 0;
+ #pragma omp parallel for reduction (y : r, s)
+ for (int i = 0; i < 64; i++)
+ {
+ r++;
+ s += i;
+ }
+ if (r != 64 || s != (64 * 63) / 2)
+ abort ();
+}
+
+int
+main ()
+{
+ A::foo ();
+ B<short>::foo ();
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-02 Jakub Jelinek <[email protected]>
PR c++/92695
* constexpr.c (cxx_eval_constant_expression) <case OBJ_TYPE_REF>: Use
STRIP_NOPS before checking for ADDR_EXPR.
* g++.dg/cpp2a/constexpr-virtual15.C: New test.
--- gcc/cp/constexpr.c (revision 278911)
+++ gcc/cp/constexpr.c (revision 278912)
@@ -5548,6 +5548,7 @@ cxx_eval_constant_expression (const cons
tree obj = OBJ_TYPE_REF_OBJECT (t);
obj = cxx_eval_constant_expression (ctx, obj, lval, non_constant_p,
overflow_p);
+ STRIP_NOPS (obj);
/* We expect something in the form of &x.D.2103.D.2094; get x. */
if (TREE_CODE (obj) != ADDR_EXPR
|| !DECL_P (get_base_address (TREE_OPERAND (obj, 0))))
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual15.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual15.C (revision 278912)
@@ -0,0 +1,7 @@
+// PR c++/92695
+// { dg-do compile { target c++2a } }
+
+struct A { virtual int get() = 0; };
+struct B : A { constexpr int get() override { return 10; } };
+struct D { B b[2]; A* c{&(b[0])}; };
+static_assert(D{}.c->get() == 10);
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-03 Jakub Jelinek <[email protected]>
PR c++/92695
* constexpr.c (cxx_bind_parameters_in_call): For virtual calls,
adjust the first argument to point to the derived object rather
than its base.
* g++.dg/cpp2a/constexpr-virtual14.C: New test.
--- gcc/cp/constexpr.c (revision 278920)
+++ gcc/cp/constexpr.c (revision 278921)
@@ -1419,6 +1419,28 @@ cxx_bind_parameters_in_call (const const
arg = adjust_temp_type (type, arg);
if (!TREE_CONSTANT (arg))
*non_constant_args = true;
+
+ /* For virtual calls, adjust the this argument, so that it is
+ the object on which the method is called, rather than
+ one of its bases. */
+ if (i == 0 && DECL_VIRTUAL_P (fun))
+ {
+ tree addr = arg;
+ STRIP_NOPS (addr);
+ if (TREE_CODE (addr) == ADDR_EXPR)
+ {
+ tree obj = TREE_OPERAND (addr, 0);
+ while (TREE_CODE (obj) == COMPONENT_REF
+ && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))
+ && !same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (obj), DECL_CONTEXT (fun)))
+ obj = TREE_OPERAND (obj, 0);
+ if (obj != TREE_OPERAND (addr, 0))
+ arg = build_fold_addr_expr_with_type (obj,
+ TREE_TYPE (arg));
+ }
+ }
+
*p = build_tree_list (parms, arg);
p = &TREE_CHAIN (*p);
}
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C (revision 278921)
@@ -0,0 +1,27 @@
+// PR c++/92695
+// { dg-do compile { target c++2a } }
+
+struct A {
+ virtual int get () = 0;
+ virtual int set (A *o) = 0;
+};
+struct B : A {
+ constexpr int get () override { return 10; }
+ constexpr int set (A *o) override { a = o; return 20; }
+ A *a {};
+};
+constexpr auto addressof = [] (A &n) { return &n; };
+struct C {
+ B b;
+ A *c { addressof (b) };
+ constexpr int add () { return c->set (addressof (b)); }
+};
+struct D {
+ B b[2];
+ A *c { addressof (b[0]) };
+ constexpr int add () { return c->set (addressof (b[0])); }
+};
+template <typename T>
+constexpr int get () { T f; return f.add (); }
+static_assert (get<C> () == 20);
+static_assert (get<D> () == 20);
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-03 Jakub Jelinek <[email protected]>
PR c++/92732
* typeck2.c (digest_nsdmi_init): For bitfields, use
DECL_BIT_FIELD_TYPE instead of TREE_TYPE.
* g++.dg/cpp2a/bitfield3.C: Don't expect narrowing conversion
warnings.
* g++.dg/cpp2a/bitfield4.C: New test.
--- gcc/cp/typeck2.c (revision 278922)
+++ gcc/cp/typeck2.c (revision 278923)
@@ -1335,6 +1335,8 @@ digest_nsdmi_init (tree decl, tree init,
gcc_assert (TREE_CODE (decl) == FIELD_DECL);
tree type = TREE_TYPE (decl);
+ if (DECL_BIT_FIELD_TYPE (decl))
+ type = DECL_BIT_FIELD_TYPE (decl);
int flags = LOOKUP_IMPLICIT;
if (DIRECT_LIST_INIT_P (init))
{
--- gcc/testsuite/g++.dg/cpp2a/bitfield3.C (revision 278922)
+++ gcc/testsuite/g++.dg/cpp2a/bitfield3.C (revision 278923)
@@ -15,11 +15,9 @@ const int b = 0;
struct S {
int c : 5 = 2 * a; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
int d : 6 { c + a }; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
- // { dg-warning "narrowing conversion
of" "" { target *-*-* } .-1 }
int e : true ? 7 : a = 3;
int f : (true ? 8 : b) = d + a; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
int g : (true ? 9 : b) { f + a }; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
- // { dg-warning "narrowing conversion
of" "" { target *-*-* } .-1 }
int h : 1 || new int { 0 };
int i = g + a;
};
@@ -28,11 +26,9 @@ template <bool V, int W>
struct U {
int j : W = 3 * a; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
int k : W { j + a }; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
- // { dg-warning "narrowing conversion
of" "" { target *-*-* } .-1 }
int l : V ? 7 : a = 3;
int m : (V ? W : b) = k + a; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
int n : (V ? W : b) { m + a }; // { dg-warning "default member
initializers for bit-fields only available with" "" { target c++17_down } }
- // { dg-warning "narrowing conversion
of" "" { target *-*-* } .-1 }
int o : 1 || new int { 0 };
int p = n + a;
};
--- gcc/testsuite/g++.dg/cpp2a/bitfield4.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp2a/bitfield4.C (revision 278923)
@@ -0,0 +1,12 @@
+// PR c++/92732
+// { dg-do compile { target c++17 } }
+// { dg-options "" }
+
+enum class byte : unsigned char { };
+using uint8_t = unsigned char;
+
+struct T
+{
+ byte a : 2 = byte{0}; // { dg-warning "default member initializers
for bit-fields only available with" "" { target c++17_down } }
+ uint8_t b : 2 = 0; // { dg-warning "default member initializers for
bit-fields only available with" "" { target c++17_down } }
+} t;
2019-12-20 Jakub Jelinek <[email protected]>
PR fortran/92756
* omp-low.c (check_omp_nesting_restrictions): If lang_GNU_Fortran,
diagnose teams not closely nested inside of target.
Backported from mainline
2019-12-04 Jakub Jelinek <[email protected]>
PR fortran/92756
* gfortran.dg/gomp/teams1.f90: New test.
--- gcc/omp-low.c.jj 2019-08-01 08:29:30.880772337 +0200
+++ gcc/omp-low.c 2019-12-20 15:29:59.052918458 +0100
@@ -3041,6 +3041,16 @@ check_omp_nesting_restrictions (gimple *
}
break;
case GIMPLE_OMP_TEAMS:
+ if ((ctx == NULL
+ || gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET
+ || gimple_omp_target_kind (ctx->stmt) != GF_OMP_TARGET_KIND_REGION)
+ && lang_GNU_Fortran ())
+ {
+ error_at (gimple_location (stmt),
+ "%<teams%> construct not closely nested inside of "
+ "%<target%> construct");
+ return false;
+ }
if (ctx == NULL)
break;
else if (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET
--- gcc/testsuite/gfortran.dg/gomp/teams1.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/gomp/teams1.f90 (revision 278956)
@@ -0,0 +1,8 @@
+! PR fortran/92756
+
+program pr92756
+ integer :: i
+ !$omp teams distribute parallel do ! { dg-error "'teams' construct not
closely nested inside of 'target' construct" }
+ do i = 1, 64
+ end do
+end
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-05 Jakub Jelinek <[email protected]>
PR fortran/92781
* trans-decl.c (gfc_get_symbol_decl): If sym->backend_decl is
current_function_decl, add length to current rather than parent
function and expect DECL_CONTEXT (length) to be current_function_decl.
* gfortran.dg/pr92781.f90: New test.
--- gcc/fortran/trans-decl.c (revision 278987)
+++ gcc/fortran/trans-decl.c (revision 278988)
@@ -1631,15 +1631,18 @@ gfc_get_symbol_decl (gfc_symbol * sym)
/* Add the string length to the same context as the symbol. */
if (DECL_CONTEXT (length) == NULL_TREE)
{
- if (DECL_CONTEXT (sym->backend_decl)
- == current_function_decl)
+ if (sym->backend_decl == current_function_decl
+ || (DECL_CONTEXT (sym->backend_decl)
+ == current_function_decl))
gfc_add_decl_to_function (length);
else
gfc_add_decl_to_parent_function (length);
}
- gcc_assert (DECL_CONTEXT (sym->backend_decl)
- == DECL_CONTEXT (length));
+ gcc_assert (sym->backend_decl == current_function_decl
+ ? DECL_CONTEXT (length) == current_function_decl
+ : (DECL_CONTEXT (sym->backend_decl)
+ == DECL_CONTEXT (length)));
gfc_defer_symbol_init (sym);
}
--- gcc/testsuite/gfortran.dg/pr92781.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/pr92781.f90 (revision 278988)
@@ -0,0 +1,11 @@
+! PR fortran/92781
+! { dg-do compile }
+
+function foo ()
+ character(:), allocatable :: foo
+ call bar ()
+ foo = 'abc'
+contains
+ subroutine bar
+ end
+end
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-06 Jakub Jelinek <[email protected]>
PR fortran/92775
* trans.h (struct lang_type, struct lang_decl): Remove span member.
(GFC_DECL_SPAN, GFC_TYPE_ARRAY_SPAN): Remove macros.
* trans-array.h (gfc_get_descriptor_offsets_for_info): Add another
argument.
* trans-array.c (gfc_get_descriptor_offsets_for_info): Add SPAN_OFF
argument and initialize *SPAN_OFF to the offset of span field.
* trans-types.c (gfc_get_array_descr_info): Adjust
gfc_get_descriptor_offsets_for_info caller. Compute elem_size
as base->span instead of TYPE_SIZE_UNIT (etype) constant.
--- gcc/fortran/trans-array.h (revision 279044)
+++ gcc/fortran/trans-array.h (revision 279045)
@@ -163,7 +163,7 @@ void gfc_trans_array_cobounds (tree, stm
/* Build expressions for accessing components of an array descriptor. */
void gfc_get_descriptor_offsets_for_info (const_tree, tree *, tree *, tree *,
tree *,
- tree *, tree *, tree *);
+ tree *, tree *, tree *, tree *);
tree gfc_conv_descriptor_data_get (tree);
tree gfc_conv_descriptor_data_addr (tree);
--- gcc/fortran/trans-array.c (revision 279044)
+++ gcc/fortran/trans-array.c (revision 279045)
@@ -540,9 +540,10 @@ gfc_conv_shift_descriptor_lbound (stmtbl
void
gfc_get_descriptor_offsets_for_info (const_tree desc_type, tree *data_off,
- tree *dtype_off, tree *dim_off,
- tree *dim_size, tree *stride_suboff,
- tree *lower_suboff, tree *upper_suboff)
+ tree *dtype_off, tree *span_off,
+ tree *dim_off, tree *dim_size,
+ tree *stride_suboff, tree *lower_suboff,
+ tree *upper_suboff)
{
tree field;
tree type;
@@ -552,6 +553,8 @@ gfc_get_descriptor_offsets_for_info (con
*data_off = byte_position (field);
field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD);
*dtype_off = byte_position (field);
+ field = gfc_advance_chain (TYPE_FIELDS (type), SPAN_FIELD);
+ *span_off = byte_position (field);
field = gfc_advance_chain (TYPE_FIELDS (type), DIMENSION_FIELD);
*dim_off = byte_position (field);
type = TREE_TYPE (TREE_TYPE (field));
--- gcc/fortran/trans-types.c (revision 279044)
+++ gcc/fortran/trans-types.c (revision 279045)
@@ -3266,7 +3266,7 @@ gfc_get_array_descr_info (const_tree typ
int rank, dim;
bool indirect = false;
tree etype, ptype, t, base_decl;
- tree data_off, dim_off, dtype_off, dim_size, elem_size;
+ tree data_off, span_off, dim_off, dtype_off, dim_size, elem_size;
tree lower_suboff, upper_suboff, stride_suboff;
tree dtype, field, rank_off;
@@ -3323,12 +3323,13 @@ gfc_get_array_descr_info (const_tree typ
if (indirect)
base_decl = build1 (INDIRECT_REF, ptype, base_decl);
- elem_size = fold_convert (gfc_array_index_type, TYPE_SIZE_UNIT (etype));
-
- gfc_get_descriptor_offsets_for_info (type, &data_off, &dtype_off, &dim_off,
- &dim_size, &stride_suboff,
+ gfc_get_descriptor_offsets_for_info (type, &data_off, &dtype_off, &span_off,
+ &dim_off, &dim_size, &stride_suboff,
&lower_suboff, &upper_suboff);
+ t = fold_build_pointer_plus (base_decl, span_off);
+ elem_size = build1 (INDIRECT_REF, gfc_array_index_type, t);
+
t = base_decl;
if (!integer_zerop (data_off))
t = fold_build_pointer_plus (t, data_off);
--- gcc/fortran/trans.h (revision 279044)
+++ gcc/fortran/trans.h (revision 279045)
@@ -981,7 +981,6 @@ struct GTY(()) lang_type {
tree offset;
tree dtype;
tree dataptr_type;
- tree span;
tree base_decl[2];
tree nonrestricted_type;
tree caf_token;
@@ -997,7 +996,6 @@ struct GTY(()) lang_decl {
address of target label. */
tree stringlen;
tree addr;
- tree span;
/* For assumed-shape coarrays. */
tree token, caf_offset;
unsigned int scalar_allocatable : 1;
@@ -1008,7 +1006,6 @@ struct GTY(()) lang_decl {
#define GFC_DECL_ASSIGN_ADDR(node) DECL_LANG_SPECIFIC(node)->addr
#define GFC_DECL_STRING_LEN(node) DECL_LANG_SPECIFIC(node)->stringlen
-#define GFC_DECL_SPAN(node) DECL_LANG_SPECIFIC(node)->span
#define GFC_DECL_TOKEN(node) DECL_LANG_SPECIFIC(node)->token
#define GFC_DECL_CAF_OFFSET(node) DECL_LANG_SPECIFIC(node)->caf_offset
#define GFC_DECL_SAVED_DESCRIPTOR(node) \
@@ -1059,7 +1056,6 @@ struct GTY(()) lang_decl {
#define GFC_TYPE_ARRAY_DTYPE(node) (TYPE_LANG_SPECIFIC(node)->dtype)
#define GFC_TYPE_ARRAY_DATAPTR_TYPE(node) \
(TYPE_LANG_SPECIFIC(node)->dataptr_type)
-#define GFC_TYPE_ARRAY_SPAN(node) (TYPE_LANG_SPECIFIC(node)->span)
#define GFC_TYPE_ARRAY_BASE_DECL(node, internal) \
(TYPE_LANG_SPECIFIC(node)->base_decl[(internal)])
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-06 Jakub Jelinek <[email protected]>
PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:
* cp-tree.h (extend_ref_init_temps): Add a new argument with NULL
default arg.
* call.c (set_up_extended_ref_temp): Add COND_GUARD argument, pass it
down to extend_ref_init_temps. Before pushing cleanup, if COND_GUARD
is non-NULL, create a bool temporary if needed, initialize to false
and guard the cleanup with the temporary being true.
(extend_ref_init_temps_1): Add COND_GUARD argument, pass it down
to recursive calls and set_up_extended_ref_temp. Handle COND_EXPR.
(extend_ref_init_temps): Add COND_GUARD argument, pass it down to
recursive calls and to extend_ref_init_temps_1.
* g++.dg/cpp0x/temp-extend2.C: New test.
--- gcc/cp/cp-tree.h (revision 279063)
+++ gcc/cp/cp-tree.h (revision 279064)
@@ -6321,7 +6321,9 @@ extern tree convert_for_arg_passing (tr
extern bool is_properly_derived_from (tree, tree);
extern tree initialize_reference (tree, tree, int,
tsubst_flags_t);
-extern tree extend_ref_init_temps (tree, tree, vec<tree,
va_gc>**);
+extern tree extend_ref_init_temps (tree, tree,
+ vec<tree, va_gc>**,
+ tree * = NULL);
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern bool type_has_extended_temps (tree);
extern tree strip_top_quals (tree);
--- gcc/cp/call.c (revision 279063)
+++ gcc/cp/call.c (revision 279064)
@@ -11449,7 +11449,7 @@ make_temporary_var_for_ref_to_temp (tree
static tree
set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
- tree *initp)
+ tree *initp, tree *cond_guard)
{
tree init;
tree type;
@@ -11480,7 +11480,8 @@ set_up_extended_ref_temp (tree decl, tre
/* Recursively extend temps in this initializer. */
TARGET_EXPR_INITIAL (expr)
- = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups);
+ = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups,
+ cond_guard);
/* Any reference temp has a non-trivial initializer. */
DECL_NONTRIVIALLY_INITIALIZED_P (var) = true;
@@ -11521,7 +11522,29 @@ set_up_extended_ref_temp (tree decl, tre
{
tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
if (cleanup)
- vec_safe_push (*cleanups, cleanup);
+ {
+ if (cond_guard && cleanup != error_mark_node)
+ {
+ if (*cond_guard == NULL_TREE)
+ {
+ *cond_guard = build_decl (input_location, VAR_DECL,
+ NULL_TREE, boolean_type_node);
+ DECL_ARTIFICIAL (*cond_guard) = 1;
+ DECL_IGNORED_P (*cond_guard) = 1;
+ DECL_CONTEXT (*cond_guard) = current_function_decl;
+ layout_decl (*cond_guard, 0);
+ add_decl_expr (*cond_guard);
+ tree set = cp_build_modify_expr (UNKNOWN_LOCATION,
+ *cond_guard, NOP_EXPR,
+ boolean_false_node,
+ tf_warning_or_error);
+ finish_expr_stmt (set);
+ }
+ cleanup = build3 (COND_EXPR, void_type_node,
+ *cond_guard, cleanup, NULL_TREE);
+ }
+ vec_safe_push (*cleanups, cleanup);
+ }
}
/* We must be careful to destroy the temporary only
@@ -11626,7 +11649,8 @@ initialize_reference (tree type, tree ex
which is bound either to a reference or a std::initializer_list. */
static tree
-extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
+extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups,
+ tree *cond_guard)
{
tree sub = init;
tree *p;
@@ -11634,20 +11658,52 @@ extend_ref_init_temps_1 (tree decl, tree
if (TREE_CODE (sub) == COMPOUND_EXPR)
{
TREE_OPERAND (sub, 1)
- = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups);
+ = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
+ cond_guard);
+ return init;
+ }
+ if (TREE_CODE (sub) == COND_EXPR)
+ {
+ tree cur_cond_guard = NULL_TREE;
+ if (TREE_OPERAND (sub, 1))
+ TREE_OPERAND (sub, 1)
+ = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
+ &cur_cond_guard);
+ if (cur_cond_guard)
+ {
+ tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
+ NOP_EXPR, boolean_true_node,
+ tf_warning_or_error);
+ TREE_OPERAND (sub, 1)
+ = cp_build_compound_expr (set, TREE_OPERAND (sub, 1),
+ tf_warning_or_error);
+ }
+ cur_cond_guard = NULL_TREE;
+ if (TREE_OPERAND (sub, 2))
+ TREE_OPERAND (sub, 2)
+ = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 2), cleanups,
+ &cur_cond_guard);
+ if (cur_cond_guard)
+ {
+ tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
+ NOP_EXPR, boolean_true_node,
+ tf_warning_or_error);
+ TREE_OPERAND (sub, 2)
+ = cp_build_compound_expr (set, TREE_OPERAND (sub, 2),
+ tf_warning_or_error);
+ }
return init;
}
if (TREE_CODE (sub) != ADDR_EXPR)
return init;
/* Deal with binding to a subobject. */
for (p = &TREE_OPERAND (sub, 0);
- (TREE_CODE (*p) == COMPONENT_REF
- || TREE_CODE (*p) == ARRAY_REF); )
+ TREE_CODE (*p) == COMPONENT_REF || TREE_CODE (*p) == ARRAY_REF; )
p = &TREE_OPERAND (*p, 0);
if (TREE_CODE (*p) == TARGET_EXPR)
{
tree subinit = NULL_TREE;
- *p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit);
+ *p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit, cond_guard);
recompute_tree_invariant_for_addr_expr (sub);
if (init != sub)
init = fold_convert (TREE_TYPE (init), sub);
@@ -11662,13 +11718,14 @@ extend_ref_init_temps_1 (tree decl, tree
lifetime to match that of DECL. */
tree
-extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
+extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups,
+ tree *cond_guard)
{
tree type = TREE_TYPE (init);
if (processing_template_decl)
return init;
if (TYPE_REF_P (type))
- init = extend_ref_init_temps_1 (decl, init, cleanups);
+ init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard);
else
{
tree ctor = init;
@@ -11681,7 +11738,8 @@ extend_ref_init_temps (tree decl, tree i
/* The temporary array underlying a std::initializer_list
is handled like a reference temporary. */
tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
- array = extend_ref_init_temps_1 (decl, array, cleanups);
+ array = extend_ref_init_temps_1 (decl, array, cleanups,
+ cond_guard);
CONSTRUCTOR_ELT (ctor, 0)->value = array;
}
else
@@ -11690,7 +11748,8 @@ extend_ref_init_temps (tree decl, tree i
constructor_elt *p;
vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
FOR_EACH_VEC_SAFE_ELT (elts, i, p)
- p->value = extend_ref_init_temps (decl, p->value, cleanups);
+ p->value = extend_ref_init_temps (decl, p->value, cleanups,
+ cond_guard);
}
recompute_constructor_flags (ctor);
if (decl_maybe_constant_var_p (decl) && TREE_CONSTANT (ctor))
--- gcc/testsuite/g++.dg/cpp0x/temp-extend2.C (nonexistent)
+++ gcc/testsuite/g++.dg/cpp0x/temp-extend2.C (revision 279064)
@@ -0,0 +1,36 @@
+// PR c++/92831
+// { dg-do run { target c++11 } }
+
+template<typename T> using id = T;
+struct S { S () { s++; } ~S () { s--; } S (int) { s++; } static int s; };
+int S::s = 0;
+
+void
+bar (bool cond, bool cond2)
+{
+ if (S::s != (cond ? cond2 ? 7 : 5 : cond2 ? 8 : 9))
+ __builtin_abort ();
+}
+
+void
+foo (bool cond, bool cond2)
+{
+ int i = 1;
+ // temporary array has same lifetime as a
+ S&& a = id<S[3]>{1, 2, 3}[i];
+ // temporary S has same lifetime as b
+ const S& b = static_cast<const S&>(0);
+ // exactly one of the four temporaries is lifetime-extended
+ S&& c = cond ? cond2 ? id<S[3]>{1, 2, 3}[i] : static_cast<S&&>(0)
+ : cond2 ? id<S[4]>{1, 2, 3, 4}[i] : id<S[5]>{1, 2, 3, 4, 5}[i];
+ bar (cond, cond2);
+}
+
+int
+main ()
+{
+ foo (true, true);
+ foo (true, false);
+ foo (false, true);
+ foo (false, false);
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-11 Jakub Jelinek <[email protected]>
PR target/92723
* tree-vect-patterns.c (vect_recog_rotate_pattern): If dt is not
vect_internal_def, use oprnd1 as is, without trying to cast it.
Formatting fix.
* gcc.dg/vect/pr92723.c: New test.
--- gcc/tree-vect-patterns.c (revision 279264)
+++ gcc/tree-vect-patterns.c (revision 279265)
@@ -2070,14 +2070,12 @@ vect_recog_rotate_pattern (stmt_vec_info
*type_out = vectype;
- if (dt == vect_external_def
- && TREE_CODE (oprnd1) == SSA_NAME)
+ if (dt == vect_external_def && TREE_CODE (oprnd1) == SSA_NAME)
ext_def = vect_get_external_def_edge (vinfo, oprnd1);
def = NULL_TREE;
scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
- if (TREE_CODE (oprnd1) == INTEGER_CST
- || TYPE_MODE (TREE_TYPE (oprnd1)) == mode)
+ if (dt != vect_internal_def || TYPE_MODE (TREE_TYPE (oprnd1)) == mode)
def = oprnd1;
else if (def_stmt && gimple_assign_cast_p (def_stmt))
{
@@ -2092,14 +2090,7 @@ vect_recog_rotate_pattern (stmt_vec_info
{
def = vect_recog_temp_ssa_var (type, NULL);
def_stmt = gimple_build_assign (def, NOP_EXPR, oprnd1);
- if (ext_def)
- {
- basic_block new_bb
- = gsi_insert_on_edge_immediate (ext_def, def_stmt);
- gcc_assert (!new_bb);
- }
- else
- append_pattern_def_seq (stmt_vinfo, def_stmt);
+ append_pattern_def_seq (stmt_vinfo, def_stmt);
}
stype = TREE_TYPE (def);
scalar_int_mode smode = SCALAR_INT_TYPE_MODE (stype);
--- gcc/testsuite/gcc.dg/vect/pr92723.c (nonexistent)
+++ gcc/testsuite/gcc.dg/vect/pr92723.c (revision 279265)
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+
+void
+foo (unsigned long long *x, unsigned long long *y, int z)
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ x[i] = (y[i] >> z) | (y[i] << (-z & (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ -
1)));
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-11 Jakub Jelinek <[email protected]>
PR fortran/92899
* trans-openmp.c (gfc_trans_omp_atomic): For GFC_OMP_ATOMIC_SWAP,
do look through conversion on expr2 if any.
* testsuite/libgomp.fortran/atomic1.f90: New test.
--- gcc/fortran/trans-openmp.c (revision 279265)
+++ gcc/fortran/trans-openmp.c (revision 279266)
@@ -3534,7 +3534,6 @@ gfc_trans_omp_atomic (gfc_code *code)
expr2 = code->expr2;
if (((atomic_code->ext.omp_atomic & GFC_OMP_ATOMIC_MASK)
!= GFC_OMP_ATOMIC_WRITE)
- && (atomic_code->ext.omp_atomic & GFC_OMP_ATOMIC_SWAP) == 0
&& expr2->expr_type == EXPR_FUNCTION
&& expr2->value.function.isym
&& expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
--- libgomp/testsuite/libgomp.fortran/atomic1.f90 (nonexistent)
+++ libgomp/testsuite/libgomp.fortran/atomic1.f90 (revision 279266)
@@ -0,0 +1,46 @@
+! PR fortran/92899
+
+program pr92899
+ real :: x = 1.0
+ double precision :: y
+ integer(kind=4) :: z = 4
+ integer(kind=8) :: w
+ !$omp atomic capture
+ y = x
+ x = 2.0
+ !$omp end atomic
+ if (y /= 1.0 .or. x /= 2.0) stop 1
+ !$omp atomic capture
+ x = y
+ y = 3.0
+ !$omp end atomic
+ if (x /= 1.0 .or. y /= 3.0) stop 2
+ !$omp atomic capture
+ w = z
+ z = 5
+ !$omp end atomic
+ if (w /= 4 .or. z /= 5) stop 3
+ !$omp atomic capture
+ z = w
+ w = 6
+ !$omp end atomic
+ if (z /= 4 .or. w /= 6) stop 4
+ !$omp atomic write
+ x = y
+ !$omp end atomic
+ if (x /= 3.0 .or. y /= 3.0) stop 5
+ x = 7.0
+ !$omp atomic write
+ y = x
+ !$omp end atomic
+ if (x /= 7.0 .or. y /= 7.0) stop 6
+ !$omp atomic write
+ z = w
+ !$omp end atomic
+ if (z /= 6 .or. w /= 6) stop 7
+ z = 8
+ !$omp atomic write
+ w = z
+ !$omp end atomic
+ if (z /= 8 .or. w /= 8) stop 8
+end
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-12 Jakub Jelinek <[email protected]>
PR target/92904
* config/i386/i386.c (ix86_gimplify_va_arg): If need_intregs and
not need_temp, decrease alignment of the read because the GPR save
area only guarantees 8-byte alignment.
* gcc.c-torture/execute/pr92904.c: New test.
--- gcc/config/i386/i386.c (revision 279326)
+++ gcc/config/i386/i386.c (revision 279327)
@@ -4277,6 +4277,7 @@ ix86_gimplify_va_arg (tree valist, tree
tree ptrtype;
machine_mode nat_mode;
unsigned int arg_boundary;
+ unsigned int type_align;
/* Only 64bit target needs something special. */
if (is_va_list_char_pointer (TREE_TYPE (valist)))
@@ -4334,6 +4335,7 @@ ix86_gimplify_va_arg (tree valist, tree
/* Pull the value out of the saved registers. */
addr = create_tmp_var (ptr_type_node, "addr");
+ type_align = TYPE_ALIGN (type);
if (container)
{
@@ -4504,6 +4506,9 @@ ix86_gimplify_va_arg (tree valist, tree
t = build2 (PLUS_EXPR, TREE_TYPE (gpr), gpr,
build_int_cst (TREE_TYPE (gpr), needed_intregs * 8));
gimplify_assign (gpr, t, pre_p);
+ /* The GPR save area guarantees only 8-byte alignment. */
+ if (!need_temp)
+ type_align = MIN (type_align, 64);
}
if (needed_sseregs)
@@ -4548,6 +4553,7 @@ ix86_gimplify_va_arg (tree valist, tree
if (container)
gimple_seq_add_stmt (pre_p, gimple_build_label (lab_over));
+ type = build_aligned_type (type, type_align);
ptrtype = build_pointer_type_for_mode (type, ptr_mode, true);
addr = fold_convert (ptrtype, addr);
--- gcc/testsuite/gcc.c-torture/execute/pr92904.c (nonexistent)
+++ gcc/testsuite/gcc.c-torture/execute/pr92904.c (revision 279327)
@@ -0,0 +1,395 @@
+/* PR target/92904 */
+
+#include <stdarg.h>
+
+struct S { long long a, b; };
+struct __attribute__((aligned (16))) T { long long a, b; };
+struct U { double a, b, c, d; };
+struct __attribute__((aligned (32))) V { double a, b, c, d; };
+struct W { double a; long long b; };
+struct __attribute__((aligned (16))) X { double a; long long b; };
+#if __SIZEOF_INT128__ == 2 * __SIZEOF_LONG_LONG__
+__int128 b;
+#endif
+struct S c;
+struct T d;
+struct U e;
+struct V f;
+struct W g;
+struct X h;
+
+#if __SIZEOF_INT128__ == 2 * __SIZEOF_LONG_LONG__
+__attribute__((noipa)) __int128
+f1 (int x, ...)
+{
+ __int128 r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, int);
+ r = va_arg (ap, __int128);
+ va_end (ap);
+ return r;
+}
+#endif
+
+__attribute__((noipa)) struct S
+f2 (int x, ...)
+{
+ struct S r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, int);
+ r = va_arg (ap, struct S);
+ va_end (ap);
+ return r;
+}
+
+__attribute__((noipa)) struct T
+f3 (int x, ...)
+{
+ struct T r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, int);
+ r = va_arg (ap, struct T);
+ va_end (ap);
+ return r;
+}
+
+#if __SIZEOF_INT128__ == 2 * __SIZEOF_LONG_LONG__
+__attribute__((noipa)) void
+f4 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, int);
+ b = va_arg (ap, __int128);
+ va_end (ap);
+}
+#endif
+
+__attribute__((noipa)) void
+f5 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, int);
+ c = va_arg (ap, struct S);
+ va_end (ap);
+}
+
+__attribute__((noipa)) void
+f6 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, int);
+ d = va_arg (ap, struct T);
+ va_end (ap);
+}
+
+__attribute__((noipa)) struct U
+f7 (int x, ...)
+{
+ struct U r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, double);
+ r = va_arg (ap, struct U);
+ va_end (ap);
+ return r;
+}
+
+__attribute__((noipa)) struct V
+f8 (int x, ...)
+{
+ struct V r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, double);
+ r = va_arg (ap, struct V);
+ va_end (ap);
+ return r;
+}
+
+__attribute__((noipa)) void
+f9 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, double);
+ e = va_arg (ap, struct U);
+ va_end (ap);
+}
+
+__attribute__((noipa)) void
+f10 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ va_arg (ap, double);
+ f = va_arg (ap, struct V);
+ va_end (ap);
+}
+
+__attribute__((noipa)) struct W
+f11 (int x, ...)
+{
+ struct W r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ {
+ va_arg (ap, int);
+ va_arg (ap, double);
+ }
+ r = va_arg (ap, struct W);
+ va_end (ap);
+ return r;
+}
+
+__attribute__((noipa)) struct X
+f12 (int x, ...)
+{
+ struct X r;
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ {
+ va_arg (ap, int);
+ va_arg (ap, double);
+ }
+ r = va_arg (ap, struct X);
+ va_end (ap);
+ return r;
+}
+
+__attribute__((noipa)) void
+f13 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ {
+ va_arg (ap, int);
+ va_arg (ap, double);
+ }
+ g = va_arg (ap, struct W);
+ va_end (ap);
+}
+
+__attribute__((noipa)) void
+f14 (int x, ...)
+{
+ va_list ap;
+ va_start (ap, x);
+ while (x--)
+ {
+ va_arg (ap, int);
+ va_arg (ap, double);
+ }
+ h = va_arg (ap, struct X);
+ va_end (ap);
+}
+
+int
+main ()
+{
+ union Y {
+#if __SIZEOF_INT128__ == 2 * __SIZEOF_LONG_LONG__
+ __int128 b;
+#endif
+ struct S c;
+ struct T d;
+ struct U e;
+ struct V f;
+ struct W g;
+ struct X h;
+ } u, v;
+ u.c.a = 0x5555555555555555ULL;
+ u.c.b = 0xaaaaaaaaaaaaaaaaULL;
+#define C(x) \
+ do { \
+ if (u.c.a != x.c.a || u.c.b != x.c.b) __builtin_abort (); \
+ u.c.a++; \
+ u.c.b--; \
+ } while (0)
+#if __SIZEOF_INT128__ == 2 * __SIZEOF_LONG_LONG__
+ v.b = f1 (0, u.b); C (v);
+ v.b = f1 (1, 0, u.b); C (v);
+ v.b = f1 (2, 0, 0, u.b); C (v);
+ v.b = f1 (3, 0, 0, 0, u.b); C (v);
+ v.b = f1 (4, 0, 0, 0, 0, u.b); C (v);
+ v.b = f1 (5, 0, 0, 0, 0, 0, u.b); C (v);
+ v.b = f1 (6, 0, 0, 0, 0, 0, 0, u.b); C (v);
+ v.b = f1 (7, 0, 0, 0, 0, 0, 0, 0, u.b); C (v);
+ v.b = f1 (8, 0, 0, 0, 0, 0, 0, 0, 0, u.b); C (v);
+ v.b = f1 (9, 0, 0, 0, 0, 0, 0, 0, 0, 0, u.b); C (v);
+#endif
+ v.c = f2 (0, u.c); C (v);
+ v.c = f2 (1, 0, u.c); C (v);
+ v.c = f2 (2, 0, 0, u.c); C (v);
+ v.c = f2 (3, 0, 0, 0, u.c); C (v);
+ v.c = f2 (4, 0, 0, 0, 0, u.c); C (v);
+ v.c = f2 (5, 0, 0, 0, 0, 0, u.c); C (v);
+ v.c = f2 (6, 0, 0, 0, 0, 0, 0, u.c); C (v);
+ v.c = f2 (7, 0, 0, 0, 0, 0, 0, 0, u.c); C (v);
+ v.c = f2 (8, 0, 0, 0, 0, 0, 0, 0, 0, u.c); C (v);
+ v.c = f2 (9, 0, 0, 0, 0, 0, 0, 0, 0, 0, u.c); C (v);
+ v.d = f3 (0, u.d); C (v);
+ v.d = f3 (1, 0, u.d); C (v);
+ v.d = f3 (2, 0, 0, u.d); C (v);
+ v.d = f3 (3, 0, 0, 0, u.d); C (v);
+ v.d = f3 (4, 0, 0, 0, 0, u.d); C (v);
+ v.d = f3 (5, 0, 0, 0, 0, 0, u.d); C (v);
+ v.d = f3 (6, 0, 0, 0, 0, 0, 0, u.d); C (v);
+ v.d = f3 (7, 0, 0, 0, 0, 0, 0, 0, u.d); C (v);
+ v.d = f3 (8, 0, 0, 0, 0, 0, 0, 0, 0, u.d); C (v);
+ v.d = f3 (9, 0, 0, 0, 0, 0, 0, 0, 0, 0, u.d); C (v);
+#if __SIZEOF_INT128__ == 2 * __SIZEOF_LONG_LONG__
+ f4 (0, u.b); v.b = b; C (v);
+ f4 (1, 0, u.b); v.b = b; C (v);
+ f4 (2, 0, 0, u.b); v.b = b; C (v);
+ f4 (3, 0, 0, 0, u.b); v.b = b; C (v);
+ f4 (4, 0, 0, 0, 0, u.b); v.b = b; C (v);
+ f4 (5, 0, 0, 0, 0, 0, u.b); v.b = b; C (v);
+ f4 (6, 0, 0, 0, 0, 0, 0, u.b); v.b = b; C (v);
+ f4 (7, 0, 0, 0, 0, 0, 0, 0, u.b); v.b = b; C (v);
+ f4 (8, 0, 0, 0, 0, 0, 0, 0, 0, u.b); v.b = b; C (v);
+ f4 (9, 0, 0, 0, 0, 0, 0, 0, 0, 0, u.b); v.b = b; C (v);
+#endif
+ f5 (0, u.c); v.c = c; C (v);
+ f5 (1, 0, u.c); v.c = c; C (v);
+ f5 (2, 0, 0, u.c); v.c = c; C (v);
+ f5 (3, 0, 0, 0, u.c); v.c = c; C (v);
+ f5 (4, 0, 0, 0, 0, u.c); v.c = c; C (v);
+ f5 (5, 0, 0, 0, 0, 0, u.c); v.c = c; C (v);
+ f5 (6, 0, 0, 0, 0, 0, 0, u.c); v.c = c; C (v);
+ f5 (7, 0, 0, 0, 0, 0, 0, 0, u.c); v.c = c; C (v);
+ f5 (8, 0, 0, 0, 0, 0, 0, 0, 0, u.c); v.c = c; C (v);
+ f5 (9, 0, 0, 0, 0, 0, 0, 0, 0, 0, u.c); v.c = c; C (v);
+ f6 (0, u.d); v.d = d; C (v);
+ f6 (1, 0, u.d); v.d = d; C (v);
+ f6 (2, 0, 0, u.d); v.d = d; C (v);
+ f6 (3, 0, 0, 0, u.d); v.d = d; C (v);
+ f6 (4, 0, 0, 0, 0, u.d); v.d = d; C (v);
+ f6 (5, 0, 0, 0, 0, 0, u.d); v.d = d; C (v);
+ f6 (6, 0, 0, 0, 0, 0, 0, u.d); v.d = d; C (v);
+ f6 (7, 0, 0, 0, 0, 0, 0, 0, u.d); v.d = d; C (v);
+ f6 (8, 0, 0, 0, 0, 0, 0, 0, 0, u.d); v.d = d; C (v);
+ f6 (9, 0, 0, 0, 0, 0, 0, 0, 0, 0, u.d); v.d = d; C (v);
+ u.e.a = 1.25;
+ u.e.b = 2.75;
+ u.e.c = -3.5;
+ u.e.d = -2.0;
+#undef C
+#define C(x) \
+ do { \
+ if (u.e.a != x.e.a || u.e.b != x.e.b \
+ || u.e.c != x.e.c || u.e.d != x.e.d) __builtin_abort ();\
+ u.e.a++; \
+ u.e.b--; \
+ u.e.c++; \
+ u.e.d--; \
+ } while (0)
+ v.e = f7 (0, u.e); C (v);
+ v.e = f7 (1, 0.0, u.e); C (v);
+ v.e = f7 (2, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (3, 0.0, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (4, 0.0, 0.0, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (5, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); C (v);
+ v.e = f7 (9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); C (v);
+ v.f = f8 (0, u.f); C (v);
+ v.f = f8 (1, 0.0, u.f); C (v);
+ v.f = f8 (2, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (3, 0.0, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (4, 0.0, 0.0, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (5, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); C (v);
+ v.f = f8 (9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); C (v);
+ f9 (0, u.e); v.e = e; C (v);
+ f9 (1, 0.0, u.e); v.e = e; C (v);
+ f9 (2, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (3, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (4, 0.0, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (5, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f9 (9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.e); v.e = e; C (v);
+ f10 (0, u.f); v.f = f; C (v);
+ f10 (1, 0.0, u.f); v.f = f; C (v);
+ f10 (2, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (3, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (4, 0.0, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (5, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ f10 (9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, u.f); v.f = f; C (v);
+ u.g.a = 9.5;
+ u.g.b = 0x5555555555555555ULL;
+#undef C
+#define C(x) \
+ do { \
+ if (u.e.a != x.e.a || u.e.b != x.e.b) __builtin_abort (); \
+ u.e.a++; \
+ u.e.b--; \
+ } while (0)
+ v.g = f11 (0, u.g); C (v);
+ v.g = f11 (1, 0, 0.0, u.g); C (v);
+ v.g = f11 (2, 0, 0.0, 0, 0.0, u.g); C (v);
+ v.g = f11 (3, 0, 0.0, 0, 0.0, 0, 0.0, u.g); C (v);
+ v.g = f11 (4, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); C (v);
+ v.g = f11 (5, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); C (v);
+ v.g = f11 (6, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); C (v);
+ v.g = f11 (7, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g);
C (v);
+ v.g = f11 (8, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0,
0.0, u.g); C (v);
+ v.g = f11 (9, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0,
0.0, 0, 0.0, u.g); C (v);
+ v.h = f12 (0, u.h); C (v);
+ v.h = f12 (1, 0, 0.0, u.h); C (v);
+ v.h = f12 (2, 0, 0.0, 0, 0.0, u.h); C (v);
+ v.h = f12 (3, 0, 0.0, 0, 0.0, 0, 0.0, u.h); C (v);
+ v.h = f12 (4, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); C (v);
+ v.h = f12 (5, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); C (v);
+ v.h = f12 (6, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); C (v);
+ v.h = f12 (7, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h);
C (v);
+ v.h = f12 (8, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0,
0.0, u.h); C (v);
+ v.h = f12 (9, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0,
0.0, 0, 0.0, u.h); C (v);
+ f13 (0, u.g); v.g = g; C (v);
+ f13 (1, 0, 0.0, u.g); v.g = g; C (v);
+ f13 (2, 0, 0.0, 0, 0.0, u.g); v.g = g; C (v);
+ f13 (3, 0, 0.0, 0, 0.0, 0, 0.0, u.g); v.g = g; C (v);
+ f13 (4, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); v.g = g; C (v);
+ f13 (5, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); v.g = g; C (v);
+ f13 (6, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); v.g = g; C (v);
+ f13 (7, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.g); v.g =
g; C (v);
+ f13 (8, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0,
u.g); v.g = g; C (v);
+ f13 (9, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0,
0.0, u.g); v.g = g; C (v);
+ f14 (0, u.h); v.h = h; C (v);
+ f14 (1, 0, 0.0, u.h); v.h = h; C (v);
+ f14 (2, 0, 0.0, 0, 0.0, u.h); v.h = h; C (v);
+ f14 (3, 0, 0.0, 0, 0.0, 0, 0.0, u.h); v.h = h; C (v);
+ f14 (4, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); v.h = h; C (v);
+ f14 (5, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); v.h = h; C (v);
+ f14 (6, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); v.h = h; C (v);
+ f14 (7, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, u.h); v.h =
h; C (v);
+ f14 (8, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0,
u.h); v.h = h; C (v);
+ f14 (9, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0,
0.0, u.h); v.h = h; C (v);
+ return 0;
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-14 Jakub Jelinek <[email protected]>
PR tree-optimization/92930
* ipa-pure-const.c (special_builtin_state): Don't handle
BUILT_IN_APPLY.
* gcc.dg/tree-ssa/pr92930.c: New test.
--- gcc/ipa-pure-const.c (revision 279393)
+++ gcc/ipa-pure-const.c (revision 279394)
@@ -527,7 +527,6 @@ special_builtin_state (enum pure_const_s
case BUILT_IN_CXA_END_CLEANUP:
case BUILT_IN_EH_COPY_VALUES:
case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_APPLY:
case BUILT_IN_APPLY_ARGS:
case BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT:
case BUILT_IN_ASAN_AFTER_DYNAMIC_INIT:
--- gcc/testsuite/gcc.dg/tree-ssa/pr92930.c (nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/pr92930.c (revision 279394)
@@ -0,0 +1,19 @@
+/* PR tree-optimization/92930 */
+/* { dg-do compile { target untyped_assembly } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "__builtin_apply " "optimized" } } */
+/* { dg-final { scan-tree-dump "__builtin_apply_args" "optimized" } } */
+
+void foo (int a, int b, int c, int d, int e, int f, int g);
+
+static void bar (int a, ...)
+{
+ __builtin_apply (foo, __builtin_apply_args (), 20);
+}
+
+int
+main ()
+{
+ bar (1024, 1025, 1026, 1027, 1028, 1029, 1030);
+ return 0;
+}
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-14 Jakub Jelinek <[email protected]>
PR ipa/92357
* ipa-fnsummary.c (ipa_fn_summary_write): Use
lto_symtab_encoder_iterator with lsei_start_function_in_partition and
lsei_next_function_in_partition instead of walking all cgraph nodes
in encoder.
--- gcc/ipa-fnsummary.c (revision 279394)
+++ gcc/ipa-fnsummary.c (revision 279395)
@@ -3452,24 +3452,24 @@ static void
ipa_fn_summary_write (void)
{
struct output_block *ob = create_output_block (LTO_section_ipa_fn_summary);
+ lto_symtab_encoder_iterator lsei;
lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
unsigned int count = 0;
- int i;
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
+ for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+ lsei_next_function_in_partition (&lsei))
{
- symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
- cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
- if (cnode && cnode->definition && !cnode->alias)
+ cgraph_node *cnode = lsei_cgraph_node (lsei);
+ if (cnode->definition && !cnode->alias)
count++;
}
streamer_write_uhwi (ob, count);
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
+ for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+ lsei_next_function_in_partition (&lsei))
{
- symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
- cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
- if (cnode && cnode->definition && !cnode->alias)
+ cgraph_node *cnode = lsei_cgraph_node (lsei);
+ if (cnode->definition && !cnode->alias)
{
struct ipa_fn_summary *info = ipa_fn_summaries->get (cnode);
struct bitpack_d bp;
2019-12-20 Jakub Jelinek <[email protected]>
Backported from mainline
2019-12-19 Jakub Jelinek <[email protected]>
PR fortran/92977
* frontend-passes.c (call_external_blas): Use || instead of |.
PR fortran/92977
* frontend-passes.c (in_omp_atomic): New variable.
(cfe_expr_0, matmul_to_var_expr, matmul_temp_args,
inline_matmul_assign, call_external_blas): Don't optimize in
EXEC_OMP_ATOMIC.
(optimize_namespace): Clear in_omp_atomic.
(gfc_code_walker): Set in_omp_atomic for EXEC_OMP_ATOMIC, save/restore
it around.
* gfortran.dg/gomp/pr92977.f90: New test.
--- gcc/fortran/frontend-passes.c (revision 279553)
+++ gcc/fortran/frontend-passes.c (revision 279554)
@@ -92,6 +92,10 @@ static int forall_level;
static bool in_omp_workshare;
+/* Keep track of whether we are within an OMP atomic. */
+
+static bool in_omp_atomic;
+
/* Keep track of whether we are within a WHERE statement. */
static bool in_where;
@@ -913,9 +917,9 @@ cfe_expr_0 (gfc_expr **e, int *walk_subt
gfc_expr *newvar;
gfc_expr **ei, **ej;
- /* Don't do this optimization within OMP workshare or ASSOC lists. */
+ /* Don't do this optimization within OMP workshare/atomic or ASSOC lists. */
- if (in_omp_workshare || in_assoc_list)
+ if (in_omp_workshare || in_omp_atomic || in_assoc_list)
{
*walk_subtrees = 0;
return 0;
@@ -1464,6 +1468,7 @@ optimize_namespace (gfc_namespace *ns)
iterator_level = 0;
in_assoc_list = false;
in_omp_workshare = false;
+ in_omp_atomic = false;
if (flag_frontend_optimize)
{
@@ -2818,7 +2823,7 @@ matmul_to_var_expr (gfc_expr **ep, int *
return 0;
if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
- || in_where || in_assoc_list)
+ || in_omp_atomic || in_where || in_assoc_list)
return 0;
/* Check if this is already in the form c = matmul(a,b). */
@@ -2880,7 +2885,7 @@ matmul_temp_args (gfc_code **c, int *wal
return 0;
if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
- || in_where)
+ || in_omp_atomic || in_where)
return 0;
/* This has some duplication with inline_matmul_assign. This
@@ -3848,7 +3853,7 @@ inline_matmul_assign (gfc_code **c, int
/* For now don't do anything in OpenMP workshare, it confuses
its translation, which expects only the allowed statements in there.
We should figure out how to parallelize this eventually. */
- if (in_omp_workshare)
+ if (in_omp_workshare || in_omp_atomic)
return 0;
expr1 = co->expr1;
@@ -4385,7 +4390,7 @@ call_external_blas (gfc_code **c, int *w
/* For now don't do anything in OpenMP workshare, it confuses
its translation, which expects only the allowed statements in there. */
- if (in_omp_workshare)
+ if (in_omp_workshare || in_omp_atomic)
return 0;
expr1 = co->expr1;
@@ -5047,6 +5052,7 @@ gfc_code_walker (gfc_code **c, walk_code
gfc_code *co;
gfc_association_list *alist;
bool saved_in_omp_workshare;
+ bool saved_in_omp_atomic;
bool saved_in_where;
/* There might be statement insertions before the current code,
@@ -5054,6 +5060,7 @@ gfc_code_walker (gfc_code **c, walk_code
co = *c;
saved_in_omp_workshare = in_omp_workshare;
+ saved_in_omp_atomic = in_omp_atomic;
saved_in_where = in_where;
switch (co->op)
@@ -5251,6 +5258,10 @@ gfc_code_walker (gfc_code **c, walk_code
WALK_SUBEXPR (co->ext.dt->extra_comma);
break;
+ case EXEC_OMP_ATOMIC:
+ in_omp_atomic = true;
+ break;
+
case EXEC_OMP_PARALLEL:
case EXEC_OMP_PARALLEL_DO:
case EXEC_OMP_PARALLEL_DO_SIMD:
@@ -5368,6 +5379,7 @@ gfc_code_walker (gfc_code **c, walk_code
select_level --;
in_omp_workshare = saved_in_omp_workshare;
+ in_omp_atomic = saved_in_omp_atomic;
in_where = saved_in_where;
}
}
--- gcc/testsuite/gfortran.dg/gomp/pr92977.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/gomp/pr92977.f90 (revision 279554)
@@ -0,0 +1,15 @@
+! PR fortran/92977
+! { dg-do compile }
+! { dg-additional-options "-O2" }
+
+program pr92977
+ integer :: n = 1
+ integer :: a
+!$omp atomic write
+ a = f(n) - f(n)
+contains
+ integer function f(x)
+ integer, intent(in) :: x
+ f = x
+ end
+end