This patch disables use of static variables in an 'omp allocate' directive
inside implicit constexpr functions. In such functions, the front end rushes
to emit RTL for static variables via 'make_rtl_for_nonlocal_decl' prior
to having even seen the allocate directive, meaning there is no clear
mechanism for how to solve this. There is a lot of history to why it is
done this way, but it is clear that it is not the correct mechanism, which
is a known issue. Unfortunately, the required redesign is rather
substantial, and outside the scope of this patchset. This issue impacts
C++17 lambdas and inline functions with '-fimplicit-constexpr'.

It can be kludged to work in templates, but since this would be
inconsistent behavior, it's best to omit the surprises and rather
just sorry, which is what we do here.

gcc/cp/ChangeLog:

        * semantics.cc (finish_omp_allocate): Add sorry.

gcc/testsuite/ChangeLog:

        * g++.dg/gomp/allocate-16.C: Remove xfails, check for sorry, modify
        cases impacted by sorry.
        * g++.dg/gomp/allocate-20.C: New test.
        * g++.dg/gomp/allocate-21.C: New test.

Signed-off-by: Waffl3x <[email protected]>
---
 gcc/cp/semantics.cc                     | 22 ++++++
 gcc/testsuite/g++.dg/gomp/allocate-16.C | 55 +++++++++-----
 gcc/testsuite/g++.dg/gomp/allocate-20.C | 96 +++++++++++++++++++++++++
 gcc/testsuite/g++.dg/gomp/allocate-21.C | 88 +++++++++++++++++++++++
 4 files changed, 243 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-20.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-21.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 00c09e119c8..c4a0a814318 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12432,6 +12432,28 @@ finish_omp_allocate (const location_t loc, const tree 
var_list,
      still need access to them when diagnosing the allocator clause.  */
   hash_set<tree> deferred_erroneous_var_nodes;
 
+  /* Due to a workaround for static local variables in implicit constexpr
+     functions, this case does not work properly.  */
+  if (any_static_vars
+      && DECL_DECLARES_FUNCTION_P (context)
+      && maybe_constexpr_fn (context))
+    {
+      auto_diagnostic_group d;
+      sorry_at (loc, "static variables are not supported in an %<allocate%> "
+                    "directive in an implicit constexpr function");
+      emit_diag_for_var_group (tree_static_p,
+                              &inform,
+                              G_("static variables appear in the "
+                                 "%<allocate%> directive here"),
+                              var_list);
+      for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn))
+       {
+         if (!tree_static_p (TREE_PURPOSE (vn)))
+           continue;
+         deferred_erroneous_var_nodes.add (vn);
+       }
+    }
+
   const auto ref_var_p
     = [] (const_tree t) -> bool { return TYPE_REF_P (TREE_TYPE (t)); };
   if (any_of_vars (ref_var_p))
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-16.C 
b/gcc/testsuite/g++.dg/gomp/allocate-16.C
index 7258d8c1c3c..12d2d763596 100644
--- a/gcc/testsuite/g++.dg/gomp/allocate-16.C
+++ b/gcc/testsuite/g++.dg/gomp/allocate-16.C
@@ -1,5 +1,4 @@
 /* { dg-do compile { target c++11 } } */
-/* { dg-ice "" { c++17 } } */
 #include "allocate-allocator-handle.h"
 
 /* Incorrect use of lambda captures in a directive or clause.
@@ -53,6 +52,8 @@ void capture_used_in_allocator_clause_static_var()
     /* { dg-error "the value of 'alloc' is not usable in a constant 
expression" "" { target *-*-* } .-1 } */
     /* { dg-error "'allocator' clause requires a constant predefined 
allocator" "" { target *-*-* } .-2 } */
     /* { dg-note "because one or more variables with static storage duration 
appear in the 'allocate' directive" "" { target *-*-* } .-3 } */
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-4 } */
+    /* { dg-note "static variables appear in the 'allocate' directive here" "" 
{ target c++17 } .-5 } */
   };
 }
 
@@ -61,14 +62,16 @@ void 
capture_used_in_allocator_clause_static_var_templ_uninstantiated()
 {
   omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note 
"'omp_allocator_handle_t alloc' is not const" "" { xfail *-*-* } } */
   auto cl = [alloc](){
-    static int a = 42; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */
+    static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++14_down 
} } */
     int b = 42;               /* { dg-bogus "'b' declared here" } */
-    static int c = 42; /* { dg-note "'c' declared here" "" { xfail *-*-* } } */
+    static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++14_down 
} } */
     int d = 42;        /* { dg-bogus "'d' declared here" } */
     #pragma omp allocate(a, b, c, d) allocator(alloc)
     /* { dg-error "the value of 'alloc' is not usable in a constant 
expression" "" { xfail *-*-* } .-1 } */
     /* { dg-error "'allocator' clause requires a constant predefined 
allocator" "" { xfail *-*-* } .-2 } */
     /* { dg-note "because one or more variables with static storage duration 
appear in the 'allocate' directive" "" { xfail *-*-* } .-3 } */
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-4 } */
+    /* { dg-note "static variables appear in the 'allocate' directive here" "" 
{ target c++17 } .-5 } */
   };
 }
 /* This case can't be diagnosed, there exists a T where alloc is a converted
@@ -79,11 +82,17 @@ void 
dependent_capture_used_in_allocator_clause_static_var_templ_uninstantiated(
 {
   T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */
   auto cl = [alloc](){
-    static int a = 42; /* { dg-bogus "'a' declared here" } */
-    static int c = 42; /* { dg-bogus "'c' declared here" } */
-    #pragma omp allocate(a, c) allocator(alloc)
+    static int a = 42; /* { dg-bogus "'a' declared here" "" { target 
c++14_down } } */
+    /* { dg-note "'a' declared here" "" { target c++17 } .-1 } */
+    int b = 42;               /* { dg-bogus "'b' declared here" } */
+    static int c = 42; /* { dg-bogus "'c' declared here" "" { target 
c++14_down } } */
+    /* { dg-note "'c' declared here" "" { target c++17 } .-1 } */
+    int d = 42;               /* { dg-bogus "'d' declared here" } */
+    #pragma omp allocate(a, b, c, d) allocator(alloc)
     /* { dg-bogus "the value of 'alloc' is not usable in a constant 
expression" "" { target *-*-* } .-1 } */
     /* { dg-bogus "because one or more variables with static storage duration 
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-3 } */
+    /* { dg-note "static variables appear in the 'allocate' directive here" "" 
{ target c++17 } .-4 } */
   };
 }
 
@@ -92,14 +101,16 @@ void capture_used_in_allocator_clause_static_var_templ()
 {
   omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note 
"'omp_allocator_handle_t alloc' is not const" "" { xfail c++17 } } */
   auto cl = [alloc](){
-    static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */
+    static int a = 42; /* { dg-note "'a' declared here" } */
     int b = 42;               /* { dg-bogus "'b' declared here" } */
-    static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */
+    static int c = 42; /* { dg-note "'c' declared here" } */
     int d = 42;        /* { dg-bogus "'d' declared here" } */
     #pragma omp allocate(a, b, c, d) allocator(alloc)
     /* { dg-error "the value of 'alloc' is not usable in a constant 
expression" "" { xfail c++17 } .-1 }*/
     /* { dg-error "'allocator' clause requires a constant predefined 
allocator" "" { xfail c++17 } .-2 } */
     /* { dg-note "because one or more variables with static storage duration 
appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-4 } */
+    /* { dg-note "static variables appear in the 'allocate' directive here" "" 
{ target c++17 } .-5 } */
   };
 }
 
@@ -108,14 +119,16 @@ void 
dependent_capture_used_in_allocator_clause_static_var_templ()
 {
   T alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t 
alloc' is not const" "" { xfail c++17 } } */
   auto cl = [alloc](){
-    static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */
+    static int a = 42; /* { dg-note "'a' declared here" } */
     int b = 42;               /* { dg-bogus "'b' declared here" } */
-    static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */
+    static int c = 42; /* { dg-note "'c' declared here" } */
     int d = 42;        /* { dg-bogus "'d' declared here" } */
     #pragma omp allocate(a, b, c, d) allocator(alloc)
     /* { dg-error "the value of 'alloc' is not usable in a constant 
expression" "" { xfail c++17 } .-1 } */
     /* { dg-error "'allocator' clause requires a constant predefined 
allocator" "" { xfail c++17 } .-2 } */
     /* { dg-note "because one or more variables with static storage duration 
appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-4 } */
+    /* { dg-note "static variables appear in the 'allocate' directive here" "" 
{ target c++17 } .-5 } */
   };
 }
 
@@ -124,11 +137,17 @@ void 
dependent_capture_used_in_allocator_clause_static_var_templ_valid()
 {
   T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */
   auto cl = [alloc](){
-    static int a = 42; /* { dg-bogus "" } */
-    static int c = 42; /* { dg-bogus "" } */
+    static int a = 42; /* { dg-bogus "'a' declared here" "" { target 
c++14_down } } */
+    /* { dg-note "'a' declared here" "" { target c++17 } .-1 } */
+    int b = 42;               /* { dg-bogus "'b' declared here" } */
+    static int c = 42; /* { dg-bogus "'c' declared here" "" { target 
c++14_down } } */
+    /* { dg-note "'c' declared here" "" { target c++17 } .-1 } */
+    int d = 42;               /* { dg-bogus "'d' declared here" } */
     #pragma omp allocate(a, c) allocator(alloc)
     /* { dg-bogus "the value of 'alloc' is not usable in a constant 
expression" "" { target *-*-* } .-1 } */
     /* { dg-bogus "'allocator' clause requires a constant predefined 
allocator" "" { target *-*-* } .-2 } */
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-3 } */
+    /* { dg-note "static variables appear in the 'allocate' directive here" "" 
{ target c++17 } .-4 } */
   };
 }
 
@@ -187,24 +206,24 @@ void 
dependent_capture_used_in_align_clause_templ_uninstantiated()
 template<typename>
 void capture_used_in_align_clause_templ()
 {
-  int align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } 
*/
+  int align = 32; /* { dg-note "'int align' is not const" } */
   auto cl = [align](){
     int a;
     #pragma omp allocate(a) align(align)
-    /* { dg-error "the value of 'align' is not usable in a constant 
expression" "" { target *-*-* xfail c++17 } .-1 } */
-    /* { dg-error "'align' clause argument needs to be positive constant power 
of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */
+    /* { dg-error "the value of 'align' is not usable in a constant 
expression" "" { target *-*-* } .-1 } */
+    /* { dg-error "'align' clause argument needs to be positive constant power 
of two integer expression" "" { target *-*-* } .-2 } */
   };
 }
 
 template<typename T>
 void dependent_capture_used_in_align_clause_templ()
 {
-  T align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } */
+  T align = 32; /* { dg-note "'int align' is not const" } */
   auto cl = [align](){
     int a;
     #pragma omp allocate(a) align(align)
-    /* { dg-error "the value of 'align' is not usable in a constant 
expression" "" { target *-*-* xfail c++17 } .-1 } */
-    /* { dg-error "'align' clause argument needs to be positive constant power 
of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */
+    /* { dg-error "the value of 'align' is not usable in a constant 
expression" "" { target *-*-* } .-1 } */
+    /* { dg-error "'align' clause argument needs to be positive constant power 
of two integer expression" "" { target *-*-* } .-2 } */
   };
 }
 
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-20.C 
b/gcc/testsuite/g++.dg/gomp/allocate-20.C
new file mode 100644
index 00000000000..d7eccf012fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-20.C
@@ -0,0 +1,96 @@
+/* { dg-do compile { target c++11 } } */
+#include "allocate-allocator-handle.h"
+
+/* Diagnose static variables used in an OpenMP allocate directive in functions
+   that are implicitly constexpr.
+   Otherwise, check that static variables have a correct alignment applied to
+   them.
+
+   This test case is valid in c++11 but the bug we are testing for does not
+   manifest until c++17, which makes lambdas implicit constexpr functions.
+   
+   For now, we simply do not support these cases.  */
+
+
+/* Making a regex for demangled identifiers is actually way harder than making
+   a regex for mangled ones, too many escapes are needed.  */
+
+/* { dg-final { scan-assembler "\.align 
256\\s*\.type\\s*_ZZZ6f0_256vENKUlvE_clEvE1a" { target c++14_down } } } */
+int* f0_256()
+{
+  auto cl = [](){
+    static int a = 42;
+    #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc)
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-1 } */
+    return &a;
+  };
+  return cl();
+}
+/* { dg-final { scan-assembler "\.align 
512\\s*\.type\\s*_ZZZ6f0_512vENKUlvE_clEvE1a" { target c++14_down } } } */
+int* f0_512()
+{
+  auto cl = [](){
+    static int a = 42;
+    #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc)
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-1 } */
+    return &a;
+  };
+  return cl();
+}
+/* { dg-final { scan-assembler "\.align 
1024\\s*\.type\\s*_ZZZ7f0_1024vENKUlvE_clEvE1a" { target c++14_down } } } */
+int* f0_1024()
+{
+  auto cl = [](){
+    static int a = 42;
+    #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc)
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-1 } */
+    return &a;
+  };
+  return cl();
+}
+
+/* { dg-final { scan-assembler "\.align 
256\\s*\.type\\s*_ZZZ6f1_256IvEPivENKUlvE_clEvE1a" { target c++14_down } } } */
+template<typename>
+int* f1_256()
+{
+  auto cl = [](){
+    static int a = 42;
+    #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc)
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-1 } */
+    return &a;
+  };
+  return cl();
+}
+template int* f1_256<void>();
+
+/* { dg-final { scan-assembler "\.align 
512\\s*\.type\\s*_ZZZ6f1_512IvEPivENKUlvE_clEvE1a" { target c++14_down } } } */
+template<typename>
+int* f1_512()
+{
+  auto cl = [](){
+    static int a = 42;
+    #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc)
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-1 } */
+    return &a;
+  };
+  return cl();
+}
+template int* f1_512<void>();
+
+/* { dg-final { scan-assembler "\.align 
1024\\s*\.type\\s*_ZZZ7f1_1024IvEPivENKUlvE_clEvE1a" { target c++14_down } } } 
*/
+template<typename>
+int* f1_1024()
+{
+  auto cl = [](){
+    static int a = 42;
+    #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc)
+    /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target c++17 } .-1 } */
+    return &a;
+  };
+  return cl();
+}
+template int* f1_1024<void>();
+
+/* Missing cases for generic lambda, and generic lambda in function template.
+   They shouldn't behave differently, but for completeness they should be
+   added, I'm just not going to spend any more time on this right now.  */
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-21.C 
b/gcc/testsuite/g++.dg/gomp/allocate-21.C
new file mode 100644
index 00000000000..7a638443f32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-21.C
@@ -0,0 +1,88 @@
+/* { dg-do compile { target c++14 } } */
+/* { dg-additional-options "-fimplicit-constexpr" } */
+#include "allocate-allocator-handle.h"
+
+/* Diagnose static variables used in an OpenMP allocate directive in functions
+   that are implicitly constexpr.
+   Inline functions and function templates with -fimplicit-constexpr.
+   
+   For now, we simply do not support these cases.
+   
+   The dg-final cases are never checked, they are kept here for demonstrating
+   intent and so they can be switched back on if these cases are fixed.  */
+
+/* Making a regex for demangled identifiers is actually way harder than making
+   a regex for mangled ones, too many escapes are needed.
+
+   We need to ODR-use the regular functions to force them to be emitted.  */
+
+/* { dg-final { scan-assembler "\.align 256\\s*\.type\\s*_ZZ6f0_256vE1a" { 
target { ! *-*-* } } } } */
+inline int* f0_256()
+{
+  static int a = 42; /* { dg-note "'a' declared here" } */
+  #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc)
+  /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target *-*-* } .-1 } */
+  /* { dg-note "static variables appear in the 'allocate' directive here" "" { 
target *-*-* } .-2 } */
+  return &a;
+}
+constexpr int*(*odr_use_f0_256)() = &f0_256;
+
+/* { dg-final { scan-assembler "\.align 512\\s*\.type\\s*_ZZ6f0_512vE1a" { 
target { ! *-*-* } } } } */
+inline int* f0_512()
+{
+  static int a = 42; /* { dg-note "'a' declared here" } */
+  #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc)
+  /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target *-*-* } .-1 } */
+  /* { dg-note "static variables appear in the 'allocate' directive here" "" { 
target *-*-* } .-2 } */
+  return &a;
+}
+constexpr int*(*odr_use_f0_512)() = &f0_512;
+
+/* { dg-final { scan-assembler "\.align 1024\\s*\.type\\s*_ZZ7f0_1024vE1a" { 
target { ! *-*-* } } } } */
+inline int* f0_1024()
+{
+  static int a = 42; /* { dg-note "'a' declared here" } */
+  #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc)
+  /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target *-*-* } .-1 } */
+  /* { dg-note "static variables appear in the 'allocate' directive here" "" { 
target *-*-* } .-2 } */
+  return &a;
+}
+constexpr int*(*odr_use_f0_1024)() = &f0_1024;
+
+
+
+/* { dg-final { scan-assembler "\.align 256\\s*\.type\\s*_ZZ6f1_256IvEPivE1a" 
{ target { ! *-*-* } } } } */
+template<typename>
+inline int* f1_256()
+{
+  static int a = 42; /* { dg-note "'a' declared here" } */
+  #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc)
+  /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target *-*-* } .-1 } */
+  /* { dg-note "static variables appear in the 'allocate' directive here" "" { 
target *-*-* } .-2 } */
+  return &a;
+}
+template int* f1_256<void>();
+
+/* { dg-final { scan-assembler "\.align 512\\s*\.type\\s*_ZZ6f1_512IvEPivE1a" 
{ target { ! *-*-* } } } } */
+template<typename>
+inline int* f1_512()
+{
+  static int a = 42; /* { dg-note "'a' declared here" } */
+  #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc)
+  /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target *-*-* } .-1 } */
+  /* { dg-note "static variables appear in the 'allocate' directive here" "" { 
target *-*-* } .-2 } */
+  return &a;
+}
+template int* f1_512<void>();
+
+/* { dg-final { scan-assembler "\.align 
1024\\s*\.type\\s*_ZZ7f1_1024IvEPivE1a" { target { ! *-*-* } } } } */
+template<typename>
+inline int* f1_1024()
+{
+  static int a = 42; /* { dg-note "'a' declared here" } */
+  #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc)
+  /* { dg-message "static variables are not supported in an 'allocate' 
directive in an implicit constexpr function" "" { target *-*-* } .-1 } */
+  /* { dg-note "static variables appear in the 'allocate' directive here" "" { 
target *-*-* } .-2 } */
+  return &a;
+}
+template int* f1_1024<void>();
-- 
2.54.0

Reply via email to