summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-11-19 22:09:01 +0100
committerJakub Jelinek <jakub@redhat.com>2021-11-19 22:09:01 +0100
commitb751b225e4f02cf0c446e659e7c3e204096468bf (patch)
treee8afbf5fd46cd99d2cc88d0f85900c8996035442
parent16d1d97626cc542d0274aa998f4e584aeab44017 (diff)
c++: Avoid adding implicit attributes during apply_late_template_attributes [PR101180]
decl_attributes and its caller cplus_decl_attributes sometimes add implicit attributes, e.g. optimize attribute if #pragma GCC optimize is active, target attribute if #pragma GCC target is active, or e.g. omp declare target attribute if in between #pragma omp declare target and #pragma omp end declare target. For templates that seems highly undesirable to me though, they should get those implicit attributes from the spot the templates were parsed (and they do get that), then tsubst through copy_node copies those attributes, but then apply_late_template_attributes can or does add a new set from the spot where they are instantiated, which can be pretty random point of first use of the template. Consider e.g. #pragma GCC push_options #pragma GCC target "avx" template <int N> inline void foo () { } #pragma GCC pop_options #pragma GCC push_options #pragma GCC target "crc32" void bar () { foo<0> (); } #pragma GCC pop_options testcase where the intention is that foo has avx target attribute and bar has crc32 target attribute, but we end up with __attribute__((target ("crc32"), target ("avx"))) on foo<0> (and due to yet another bug actually don't enable avx in foo<0>). In this particular case it is a regression caused by r12-299-ga0fdff3cf33f7284 which apparently calls cplus_decl_attributes even if attributes != NULL but late_attrs is NULL, before those changes we didn't call it in those cases. But, if there is at least one unrelated dependent attribute this would happen already in older releases. The following patch fixes that by temporarily overriding the variables that control the addition of the implicit attributes. Shall we also change the function so that it doesn't call cplus_decl_attributes if late_attrs is NULL, or was that change intentional? 2021-11-19 Jakub Jelinek <jakub@redhat.com> PR c++/101180 * pt.c (apply_late_template_attributes): Temporarily override current_optimize_pragma, optimization_current_node, current_target_pragma and scope_chain->omp_declare_target_attribute, so that cplus_decl_attributes doesn't add implicit attributes. * g++.target/i386/pr101180.C: New test.
-rw-r--r--gcc/cp/pt.c11
-rw-r--r--gcc/testsuite/g++.target/i386/pr101180.C25
2 files changed, 36 insertions, 0 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 22798b91608..c73e035d8b8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11727,6 +11727,17 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
q = &TREE_CHAIN (*q);
}
+ /* cplus_decl_attributes can add some attributes implicitly. For templates,
+ those attributes should have been added already when those templates were
+ parsed, and shouldn't be added based on from which context they are
+ first time instantiated. */
+ auto o1 = make_temp_override (current_optimize_pragma, NULL_TREE);
+ auto o2 = make_temp_override (optimization_current_node,
+ optimization_default_node);
+ auto o3 = make_temp_override (current_target_pragma, NULL_TREE);
+ auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute,
+ NULL);
+
cplus_decl_attributes (decl_p, late_attrs, attr_flags);
return true;
diff --git a/gcc/testsuite/g++.target/i386/pr101180.C b/gcc/testsuite/g++.target/i386/pr101180.C
new file mode 100644
index 00000000000..483070835aa
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr101180.C
@@ -0,0 +1,25 @@
+// PR c++/101180
+// { dg-do compile { target c++11 } }
+
+#pragma GCC target "avx"
+template <typename> struct A {};
+#pragma GCC push_options
+#pragma GCC target "avx,avx2,bmi,bmi2,fma,f16c"
+template <typename T> using B = A<T>;
+template <typename> struct C;
+template <> struct C<float> {
+ __attribute__((always_inline)) float operator()(long) { return .0f; }
+};
+long d;
+template <typename T> void e(B<T>) {
+ T{C<T>()(d)};
+}
+template <typename T, typename FromT> void f(T d, FromT) {
+ e(d);
+}
+int g;
+void h() {
+ A<float> i;
+ f(i, g);
+}
+#pragma GCC pop_options