[clang] dd4c838 - [OpenMP] Allow data members in interop init/use/destroy clauses

Mike Rice via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 11 09:39:45 PDT 2022


Author: Mike Rice
Date: 2022-08-11T09:39:12-07:00
New Revision: dd4c838da30ad4b6d5dc0f700df0a6629469f719

URL: https://github.com/llvm/llvm-project/commit/dd4c838da30ad4b6d5dc0f700df0a6629469f719
DIFF: https://github.com/llvm/llvm-project/commit/dd4c838da30ad4b6d5dc0f700df0a6629469f719.diff

LOG: [OpenMP] Allow data members in interop init/use/destroy clauses

Previously a diagnostic was given if the expression was not strictly a
DeclRef. Now also allow use of data members inside member functions.

Differential Revision: https://reviews.llvm.org/D131222

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaOpenMP.cpp
    clang/test/OpenMP/interop_ast_print.cpp
    clang/test/OpenMP/interop_irbuilder.cpp
    clang/test/OpenMP/interop_messages.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 92217aed89747..e4e7d7b7338a4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10387,6 +10387,9 @@ def err_omp_unexpected_clause_value : Error<
   "expected %0 in OpenMP clause '%1'">;
 def err_omp_expected_var_name_member_expr : Error<
   "expected variable name%select{| or data member of current class}0">;
+def err_omp_expected_var_name_member_expr_with_type : Error<
+  "expected variable%select{| or static data member|, static data member, "
+  "or non-static data member of current class}0 of type '%1'">;
 def err_omp_expected_var_name_member_expr_or_array_item : Error<
   "expected variable name%select{|, data member of current class}0, array element or array section">;
 def err_omp_expected_addressable_lvalue_or_array_item : Error<

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 3b1aab6ca0e5f..1d9ec1162bafb 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -2718,7 +2718,8 @@ void Sema::EndOpenMPClause() {
 
 static std::pair<ValueDecl *, bool>
 getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
-               SourceRange &ERange, bool AllowArraySection = false);
+               SourceRange &ERange, bool AllowArraySection = false,
+               StringRef DiagType = "");
 
 /// Check consistency of the reduction clauses.
 static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
@@ -5279,7 +5280,8 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
 static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
                                                    SourceLocation &ELoc,
                                                    SourceRange &ERange,
-                                                   bool AllowArraySection) {
+                                                   bool AllowArraySection,
+                                                   StringRef DiagType) {
   if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
       RefExpr->containsUnexpandedParameterPack())
     return std::make_pair(nullptr, true);
@@ -5324,6 +5326,12 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
     if (IsArrayExpr != NoArrayExpr) {
       S.Diag(ELoc, diag::err_omp_expected_base_var_name)
           << IsArrayExpr << ERange;
+    } else if (!DiagType.empty()) {
+      unsigned DiagSelect = S.getLangOpts().CPlusPlus
+                                ? (S.getCurrentThisType().isNull() ? 1 : 2)
+                                : 0;
+      S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr_with_type)
+          << DiagSelect << DiagType << ERange;
     } else {
       S.Diag(ELoc,
              AllowArraySection
@@ -17249,32 +17257,28 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
   // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
   // Each interop-var may be specified for at most one action-clause of each
   // interop construct.
-  llvm::SmallPtrSet<const VarDecl *, 4> InteropVars;
-  for (const OMPClause *C : Clauses) {
+  llvm::SmallPtrSet<const ValueDecl *, 4> InteropVars;
+  for (OMPClause *C : Clauses) {
     OpenMPClauseKind ClauseKind = C->getClauseKind();
-    const DeclRefExpr *DRE = nullptr;
-    SourceLocation VarLoc;
+    std::pair<ValueDecl *, bool> DeclResult;
+    SourceLocation ELoc;
+    SourceRange ERange;
 
     if (ClauseKind == OMPC_init) {
-      const auto *IC = cast<OMPInitClause>(C);
-      VarLoc = IC->getVarLoc();
-      DRE = dyn_cast_or_null<DeclRefExpr>(IC->getInteropVar());
+      auto *E = cast<OMPInitClause>(C)->getInteropVar();
+      DeclResult = getPrivateItem(*this, E, ELoc, ERange);
     } else if (ClauseKind == OMPC_use) {
-      const auto *UC = cast<OMPUseClause>(C);
-      VarLoc = UC->getVarLoc();
-      DRE = dyn_cast_or_null<DeclRefExpr>(UC->getInteropVar());
+      auto *E = cast<OMPUseClause>(C)->getInteropVar();
+      DeclResult = getPrivateItem(*this, E, ELoc, ERange);
     } else if (ClauseKind == OMPC_destroy) {
-      const auto *DC = cast<OMPDestroyClause>(C);
-      VarLoc = DC->getVarLoc();
-      DRE = dyn_cast_or_null<DeclRefExpr>(DC->getInteropVar());
+      auto *E = cast<OMPDestroyClause>(C)->getInteropVar();
+      DeclResult = getPrivateItem(*this, E, ELoc, ERange);
     }
 
-    if (!DRE)
-      continue;
-
-    if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
-      if (!InteropVars.insert(VD->getCanonicalDecl()).second) {
-        Diag(VarLoc, diag::err_omp_interop_var_multiple_actions) << VD;
+    if (DeclResult.first) {
+      if (!InteropVars.insert(DeclResult.first).second) {
+        Diag(ELoc, diag::err_omp_interop_var_multiple_actions)
+            << DeclResult.first;
         return StmtError();
       }
     }
@@ -17286,16 +17290,20 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
 static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
                                    SourceLocation VarLoc,
                                    OpenMPClauseKind Kind) {
-  if (InteropVarExpr->isValueDependent() || InteropVarExpr->isTypeDependent() ||
-      InteropVarExpr->isInstantiationDependent() ||
-      InteropVarExpr->containsUnexpandedParameterPack())
+  SourceLocation ELoc;
+  SourceRange ERange;
+  Expr *RefExpr = InteropVarExpr;
+  auto Res =
+      getPrivateItem(SemaRef, RefExpr, ELoc, ERange,
+                     /*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t");
+
+  if (Res.second) {
+    // It will be analyzed later.
     return true;
+  }
 
-  const auto *DRE = dyn_cast<DeclRefExpr>(InteropVarExpr);
-  if (!DRE || !isa<VarDecl>(DRE->getDecl())) {
-    SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected) << 0;
+  if (!Res.first)
     return false;
-  }
 
   // Interop variable should be of type omp_interop_t.
   bool HasError = false;

diff  --git a/clang/test/OpenMP/interop_ast_print.cpp b/clang/test/OpenMP/interop_ast_print.cpp
index 8f8ddc839c722..1a492fb0a8319 100644
--- a/clang/test/OpenMP/interop_ast_print.cpp
+++ b/clang/test/OpenMP/interop_ast_print.cpp
@@ -23,6 +23,57 @@
 
 typedef void *omp_interop_t;
 
+struct S {
+  omp_interop_t o1;
+  omp_interop_t o2;
+  omp_interop_t o3;
+  static omp_interop_t so;
+  void foo();
+  S();
+  ~S();
+};
+omp_interop_t S::so;
+
+struct T {
+  static void static_member_func();
+  static omp_interop_t to;
+};
+omp_interop_t T::to;
+
+void T::static_member_func() {
+  omp_interop_t o1;
+  //PRINT: #pragma omp interop init(target : o1)
+  #pragma omp interop init(target:o1)
+
+  //PRINT: #pragma omp interop init(target : to)
+  #pragma omp interop init(target: to)
+
+  //PRINT: #pragma omp interop init(target : T::to)
+  #pragma omp interop init(target: T::to)
+
+  //PRINT: #pragma omp interop init(target : S::so)
+  #pragma omp interop init(target: S::so)
+}
+
+
+S::S() {
+  //PRINT: #pragma omp interop init(target : this->o1)
+  #pragma omp interop init(target:o1)
+  //PRINT: #pragma omp interop use(this->o1) init(target : this->o2)
+  #pragma omp interop use(o1) init(target:o2)
+  //PRINT: #pragma omp interop use(this->o2) init(target : this->o3)
+  #pragma omp interop use(o2) init(target:o3)
+}
+S::~S() {
+  //PRINT: #pragma omp interop destroy(this->o1) destroy(this->o2) destroy(this->o3)
+  #pragma omp interop destroy(o1) destroy(o2) destroy(o3)
+}
+
+void S::foo() {
+  //PRINT: #pragma omp interop init(target : so)
+  #pragma omp interop init(target:so)
+}
+
 //PRINT-LABEL: void foo1(
 //DUMP-LABEL:  FunctionDecl {{.*}} foo1
 void foo1(int *ap, int dev) {
@@ -196,6 +247,9 @@ void foo1(int *ap, int dev) {
   //DUMP: OMPUseClause
   //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'J'
   #pragma omp interop destroy(I) use(J)
+
+  //PRINT: #pragma omp interop init(target : S::so)
+  #pragma omp interop init(target: S::so)
 }
 
 //DUMP: FunctionTemplateDecl{{.*}}fooTemp
@@ -274,6 +328,7 @@ void bar()
   fooTemp<3>();
   omp_interop_t Ivar;
   barTemp(Ivar);
+  S s;
 }
 
 #endif // HEADER

diff  --git a/clang/test/OpenMP/interop_irbuilder.cpp b/clang/test/OpenMP/interop_irbuilder.cpp
index bd18caa21423c..2cf2d56f16371 100644
--- a/clang/test/OpenMP/interop_irbuilder.cpp
+++ b/clang/test/OpenMP/interop_irbuilder.cpp
@@ -29,6 +29,34 @@ void test1() {
                                             : D0, D1)
 }
 
+struct S {
+  omp_interop_t interop;
+  void member_test();
+};
+
+void S::member_test() {
+
+  int device_id = 4;
+  int D0, D1;
+
+#pragma omp interop init(target \
+                         : interop)
+
+#pragma omp interop init(targetsync \
+                         : interop)
+
+#pragma omp interop init(target \
+                         : interop) device(device_id)
+
+#pragma omp interop init(targetsync \
+                         : interop) device(device_id)
+
+#pragma omp interop use(interop) depend(in \
+                                        : D0, D1) nowait
+
+#pragma omp interop destroy(interop) depend(in \
+                                            : D0, D1)
+}
 // CHECK-LABEL: @_Z5test1v(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[DEVICE_ID:%.*]] = alloca i32, align 4
@@ -94,3 +122,77 @@ void test1() {
 // CHECK-NEXT:    call void @__tgt_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP25]], i32 0)
 // CHECK-NEXT:    ret void
 //
+//
+// CHECK-LABEL: @_ZN1S11member_testEv(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca %struct.S*, align 8
+// CHECK-NEXT:    [[DEVICE_ID:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[D0:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[D1:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTDEP_ARR_ADDR:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8
+// CHECK-NEXT:    [[DEP_COUNTER_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    [[DOTDEP_ARR_ADDR10:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8
+// CHECK-NEXT:    [[DEP_COUNTER_ADDR11:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    store %struct.S* [[THIS:%.*]], %struct.S** [[THIS_ADDR]], align 8
+// CHECK-NEXT:    [[THIS1:%.*]] = load %struct.S*, %struct.S** [[THIS_ADDR]], align 8
+// CHECK-NEXT:    store i32 4, i32* [[DEVICE_ID]], align 4
+// CHECK-NEXT:    [[INTEROP:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], %struct.S* [[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
+// CHECK-NEXT:    call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i8** [[INTEROP]], i64 1, i32 -1, i32 0, i8* null, i32 0)
+// CHECK-NEXT:    [[INTEROP2:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
+// CHECK-NEXT:    call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], i8** [[INTEROP2]], i64 2, i32 -1, i32 0, i8* null, i32 0)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[DEVICE_ID]], align 4
+// CHECK-NEXT:    [[INTEROP4:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM5:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
+// CHECK-NEXT:    call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM5]], i8** [[INTEROP4]], i64 1, i32 [[TMP0]], i32 0, i8* null, i32 0)
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[DEVICE_ID]], align 4
+// CHECK-NEXT:    [[INTEROP6:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
+// CHECK-NEXT:    call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP6]], i64 2, i32 [[TMP1]], i32 0, i8* null, i32 0)
+// CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR]], i64 0, i64 0
+// CHECK-NEXT:    [[TMP3:%.*]] = ptrtoint i32* [[D0]] to i64
+// CHECK-NEXT:    [[TMP4:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], %struct.kmp_depend_info* [[TMP2]], i64 0
+// CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP4]], i32 0, i32 0
+// CHECK-NEXT:    store i64 [[TMP3]], i64* [[TMP5]], align 8
+// CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP4]], i32 0, i32 1
+// CHECK-NEXT:    store i64 4, i64* [[TMP6]], align 8
+// CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP4]], i32 0, i32 2
+// CHECK-NEXT:    store i8 1, i8* [[TMP7]], align 8
+// CHECK-NEXT:    [[TMP8:%.*]] = ptrtoint i32* [[D1]] to i64
+// CHECK-NEXT:    [[TMP9:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP2]], i64 1
+// CHECK-NEXT:    [[TMP10:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP9]], i32 0, i32 0
+// CHECK-NEXT:    store i64 [[TMP8]], i64* [[TMP10]], align 8
+// CHECK-NEXT:    [[TMP11:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP9]], i32 0, i32 1
+// CHECK-NEXT:    store i64 4, i64* [[TMP11]], align 8
+// CHECK-NEXT:    [[TMP12:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP9]], i32 0, i32 2
+// CHECK-NEXT:    store i8 1, i8* [[TMP12]], align 8
+// CHECK-NEXT:    store i64 2, i64* [[DEP_COUNTER_ADDR]], align 8
+// CHECK-NEXT:    [[TMP13:%.*]] = bitcast %struct.kmp_depend_info* [[TMP2]] to i8*
+// CHECK-NEXT:    [[INTEROP8:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM9:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
+// CHECK-NEXT:    call void @__tgt_interop_use(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM9]], i8** [[INTEROP8]], i32 -1, i32 2, i8* [[TMP13]], i32 1)
+// CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR10]], i64 0, i64 0
+// CHECK-NEXT:    [[TMP15:%.*]] = ptrtoint i32* [[D0]] to i64
+// CHECK-NEXT:    [[TMP16:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 0
+// CHECK-NEXT:    [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP16]], i32 0, i32 0
+// CHECK-NEXT:    store i64 [[TMP15]], i64* [[TMP17]], align 8
+// CHECK-NEXT:    [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP16]], i32 0, i32 1
+// CHECK-NEXT:    store i64 4, i64* [[TMP18]], align 8
+// CHECK-NEXT:    [[TMP19:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP16]], i32 0, i32 2
+// CHECK-NEXT:    store i8 1, i8* [[TMP19]], align 8
+// CHECK-NEXT:    [[TMP20:%.*]] = ptrtoint i32* [[D1]] to i64
+// CHECK-NEXT:    [[TMP21:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 1
+// CHECK-NEXT:    [[TMP22:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP21]], i32 0, i32 0
+// CHECK-NEXT:    store i64 [[TMP20]], i64* [[TMP22]], align 8
+// CHECK-NEXT:    [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP21]], i32 0, i32 1
+// CHECK-NEXT:    store i64 4, i64* [[TMP23]], align 8
+// CHECK-NEXT:    [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP21]], i32 0, i32 2
+// CHECK-NEXT:    store i8 1, i8* [[TMP24]], align 8
+// CHECK-NEXT:    store i64 2, i64* [[DEP_COUNTER_ADDR11]], align 8
+// CHECK-NEXT:    [[TMP25:%.*]] = bitcast %struct.kmp_depend_info* [[TMP14]] to i8*
+// CHECK-NEXT:    [[INTEROP12:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM13:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
+// CHECK-NEXT:    call void @__tgt_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM13]], i8** [[INTEROP12]], i32 -1, i32 2, i8* [[TMP25]], i32 0)
+// CHECK-NEXT:    ret void
+//

diff  --git a/clang/test/OpenMP/interop_messages.cpp b/clang/test/OpenMP/interop_messages.cpp
index 50f1efb5a6a9b..8707b5d89cf38 100644
--- a/clang/test/OpenMP/interop_messages.cpp
+++ b/clang/test/OpenMP/interop_messages.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - -DWITHDEF %s
 // RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - -DWITHOUTDEF %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c99 -x c -o - -DCTEST %s
 
 #ifdef WITHDEF
 typedef void *omp_interop_t;
@@ -55,13 +56,13 @@ void foo(int *Ap) {
   #pragma omp interop destroy(SVar) destroy(Another)
 
   int a, b;
-  //expected-error at +1 {{expected variable of type 'omp_interop_t'}}
+  //expected-error at +1 {{expected variable or static data member of type 'omp_interop_t'}}
   #pragma omp interop init(target:a+b) init(target:Another)
 
-  //expected-error at +1 {{expected variable of type 'omp_interop_t'}}
+  //expected-error at +1 {{expected variable or static data member of type 'omp_interop_t'}}
   #pragma omp interop use(a+b) use(Another)
 
-  //expected-error at +1 {{expected variable of type 'omp_interop_t'}}
+  //expected-error at +1 {{expected variable or static data member of type 'omp_interop_t'}}
   #pragma omp interop destroy(a+b) destroy(Another)
 
   const omp_interop_t C = (omp_interop_t)5;
@@ -115,6 +116,61 @@ void foo(int *Ap) {
   //expected-error at +1 {{directive '#pragma omp interop' cannot contain more than one 'nowait' clause}}
   #pragma omp interop nowait init(target:InteropVar) nowait
 }
+
+struct S {
+  void foo();
+  omp_interop_t InteropVar;
+  omp_interop_t func();
+  static omp_interop_t sfunc();
+};
+
+struct T {
+  static void static_member_func();
+};
+
+void T::static_member_func() {
+  S s;
+  omp_interop_t o;
+
+  //expected-error at +1 {{expected variable or static data member of type 'omp_interop_t'}}
+  #pragma omp interop init(target:s.InteropVar) init(target:o)
+}
+
+void S::foo() {
+  //expected-error at +1 {{interop variable 'InteropVar' used in multiple action clauses}}
+  #pragma omp interop init(target:InteropVar) init(target:InteropVar)
+
+  //expected-error at +1 {{interop variable 'InteropVar' used in multiple action clauses}}
+  #pragma omp interop use(InteropVar) use(InteropVar)
+
+  //expected-error at +1 {{interop variable 'InteropVar' used in multiple action clauses}}
+  #pragma omp interop destroy(InteropVar) destroy(InteropVar)
+
+  //expected-error at +1 {{interop variable 'InteropVar' used in multiple action clauses}}
+  #pragma omp interop init(target:InteropVar) use(InteropVar)
+
+  //expected-error at +1 {{interop variable 'InteropVar' used in multiple action clauses}}
+  #pragma omp interop init(target:InteropVar) destroy(InteropVar)
+
+  //expected-error at +1 {{interop variable 'InteropVar' used in multiple action clauses}}
+  #pragma omp interop use(InteropVar) destroy(InteropVar)
+
+  //expected-error at +1 {{expected variable, static data member, or non-static data member of current class of type 'omp_interop_t'}}
+  #pragma omp interop init(target:InteropVar) init(target:func())
+
+  //expected-error at +1 {{expected variable, static data member, or non-static data member of current class of type 'omp_interop_t'}}
+  #pragma omp interop init(target:InteropVar) init(target:sfunc())
+}
+
+void foo2() {
+  S s;
+  omp_interop_t another;
+  //expected-error at +1 {{expected variable or static data member of type 'omp_interop_t'}}
+  #pragma omp interop init(target:s.InteropVar) init(target:another)
+
+  //expected-error at +1 {{expected variable or static data member of type 'omp_interop_t'}}
+  #pragma omp interop init(target: S::sfunc()) init(target:another)
+}
 #endif
 #ifdef WITHOUTDEF
 void foo() {
@@ -127,3 +183,20 @@ void foo() {
   #pragma omp interop destroy(InteropVar) nowait
 }
 #endif
+#ifdef CTEST
+typedef void *omp_interop_t;
+omp_interop_t bar();
+struct S {
+  omp_interop_t o;
+};
+void foo() {
+  omp_interop_t o;
+  struct S s;
+
+  //expected-error at +1 {{expected variable of type 'omp_interop_t'}}
+  #pragma omp interop init(target:o) init(target:bar())
+
+  //expected-error at +1 {{expected variable of type 'omp_interop_t'}}
+  #pragma omp interop init(target:o) init(target:s.o)
+}
+#endif


        


More information about the cfe-commits mailing list