[clang] fa20b5d - [OpenACC] 'if' and 'self' clause implementation for Combined Constructs

via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 13 12:43:04 PST 2024


Author: erichkeane
Date: 2024-11-13T12:42:53-08:00
New Revision: fa20b5d30d38f4bb090acac7c205fbb54a5ca990

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

LOG: [OpenACC] 'if' and 'self' clause implementation for Combined Constructs

These two are identical to how they work for compute constructs, so this
patch enables them and ensures there is sufficient testing.

Added: 
    clang/test/SemaOpenACC/combined-construct-if-ast.cpp
    clang/test/SemaOpenACC/combined-construct-if-clause.c
    clang/test/SemaOpenACC/combined-construct-if-clause.cpp
    clang/test/SemaOpenACC/combined-construct-self-ast.cpp
    clang/test/SemaOpenACC/combined-construct-self-clause.c
    clang/test/SemaOpenACC/combined-construct-self-clause.cpp

Modified: 
    clang/lib/Sema/SemaOpenACC.cpp
    clang/test/AST/ast-print-openacc-combined-construct.cpp
    clang/test/ParserOpenACC/parse-clauses.c
    clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c
    clang/test/SemaOpenACC/compute-construct-default-clause.c
    clang/test/SemaOpenACC/compute-construct-if-clause.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 78953a89f65e30..dd6558d0afed70 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -626,10 +626,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitTileClause(
 
 OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
     SemaOpenACC::OpenACCParsedClause &Clause) {
-  // Restrictions only properly implemented on 'compute' constructs, and
-  // 'compute' constructs are the only construct that can do anything with
-  // this yet, so skip/treat as unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+  // Restrictions only properly implemented on 'compute'/'combined' constructs,
+  // and 'compute'/'combined' constructs are the only construct that can do
+  // anything with this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
+      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // There is no prose in the standard that says duplicates aren't allowed,
@@ -662,7 +663,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause(
   // Restrictions only properly implemented on 'compute' constructs, and
   // 'compute' constructs are the only construct that can do anything with
   // this yet, so skip/treat as unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
+      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // TODO OpenACC: When we implement this for 'update', this takes a

diff  --git a/clang/test/AST/ast-print-openacc-combined-construct.cpp b/clang/test/AST/ast-print-openacc-combined-construct.cpp
index d77465c69f4acb..b2a6799deb3fce 100644
--- a/clang/test/AST/ast-print-openacc-combined-construct.cpp
+++ b/clang/test/AST/ast-print-openacc-combined-construct.cpp
@@ -71,5 +71,19 @@ void foo() {
 #pragma acc kernels loop dtype(AnotherIdent)
   for(int i = 0;i<5;++i);
 
+  int i;
+  float array[5];
+
+// CHECK: #pragma acc parallel self(i == 3)
+// CHECK-NEXT: for (int i = 0; i < 5; ++i)
+// CHECK-NEXT: ;
+#pragma acc parallel loop self(i == 3)
+  for(int i = 0;i<5;++i);
+
+// CHECK: #pragma acc kernels if(i == array[1])
+// CHECK-NEXT: for (int i = 0; i < 5; ++i)
+// CHECK-NEXT: ;
+#pragma acc kernels if(i == array[1])
+  for(int i = 0;i<5;++i);
 
 }

diff  --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c
index a0e01ef5a85a62..656b31444a9eed 100644
--- a/clang/test/ParserOpenACC/parse-clauses.c
+++ b/clang/test/ParserOpenACC/parse-clauses.c
@@ -266,11 +266,9 @@ void IfClause() {
 }
 
 void SelfClause() {
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented, clause ignored}}
 #pragma acc serial loop self
   for(int i = 0; i < 5;++i) {}
 
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented, clause ignored}}
 #pragma acc serial loop self, seq
   for(int i = 0; i < 5;++i) {}
 
@@ -293,18 +291,15 @@ void SelfClause() {
 #pragma acc serial loop self(, seq
   for(int i = 0; i < 5;++i) {}
 
-  // expected-error at +2{{expected identifier}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented, clause ignored}}
+  // expected-error at +1{{expected identifier}}
 #pragma acc serial loop self)
   for(int i = 0; i < 5;++i) {}
 
-  // expected-error at +2{{expected identifier}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented, clause ignored}}
+  // expected-error at +1{{expected identifier}}
 #pragma acc serial loop self) seq
   for(int i = 0; i < 5;++i) {}
 
-  // expected-error at +2{{expected identifier}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented, clause ignored}}
+  // expected-error at +1{{expected identifier}}
 #pragma acc serial loop self), seq
   for(int i = 0; i < 5;++i) {}
 

diff  --git a/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c b/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c
index 95cc7a7ed22949..8a062b6ac1d5d6 100644
--- a/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c
+++ b/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c
@@ -60,12 +60,8 @@ void uses() {
   // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
 #pragma acc parallel loop auto default(none)
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'if' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop auto if(1)
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'self' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented}}
 #pragma acc parallel loop auto self
   for(unsigned i = 0; i < 5; ++i);
   // TODOexpected-error at +1{{OpenACC 'copy' clause is not valid on 'parallel loop' directive}}
@@ -234,12 +230,8 @@ void uses() {
   // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
 #pragma acc parallel loop default(none) auto
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'if' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop if(1) auto
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'self' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented}}
 #pragma acc parallel loop self auto
   for(unsigned i = 0; i < 5; ++i);
   // TODOexpected-error at +1{{OpenACC 'copy' clause is not valid on 'parallel loop' directive}}
@@ -409,12 +401,8 @@ void uses() {
   // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
 #pragma acc parallel loop independent default(none)
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'if' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop independent if(1)
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'self' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented}}
 #pragma acc parallel loop independent self
   for(unsigned i = 0; i < 5; ++i);
   // TODOexpected-error at +1{{OpenACC 'copy' clause is not valid on 'parallel loop' directive}}
@@ -583,12 +571,8 @@ void uses() {
   // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
 #pragma acc parallel loop default(none) independent
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'if' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop if(1) independent
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'self' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented}}
 #pragma acc parallel loop self independent
   for(unsigned i = 0; i < 5; ++i);
   // TODOexpected-error at +1{{OpenACC 'copy' clause is not valid on 'parallel loop' directive}}
@@ -764,12 +748,8 @@ void uses() {
   // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
 #pragma acc parallel loop seq default(none)
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'if' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop seq if(1)
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'self' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented}}
 #pragma acc parallel loop seq self
   for(unsigned i = 0; i < 5; ++i);
   // TODOexpected-error at +1{{OpenACC 'copy' clause is not valid on 'parallel loop' directive}}
@@ -944,12 +924,8 @@ void uses() {
   // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
 #pragma acc parallel loop default(none) seq
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'if' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop if(1) seq
   for(unsigned i = 0; i < 5; ++i);
-  // TODOexpected-error at +1{{OpenACC 'self' clause is not valid on 'parallel loop' directive}}
-  // expected-warning at +1{{OpenACC clause 'self' not yet implemented}}
 #pragma acc parallel loop self seq
   for(unsigned i = 0; i < 5; ++i);
   // TODOexpected-error at +1{{OpenACC 'copy' clause is not valid on 'parallel loop' directive}}

diff  --git a/clang/test/SemaOpenACC/combined-construct-if-ast.cpp b/clang/test/SemaOpenACC/combined-construct-if-ast.cpp
new file mode 100644
index 00000000000000..f0796409d942d7
--- /dev/null
+++ b/clang/test/SemaOpenACC/combined-construct-if-ast.cpp
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s
+
+// Test this with PCH.
+// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s
+// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s
+
+#ifndef PCH_HELPER
+#define PCH_HELPER
+void NormalFunc(int j, float f) {
+  // CHECK: FunctionDecl{{.*}}NormalFunc
+  // CHECK-NEXT: ParmVarDecl
+  // CHECK-NEXT: ParmVarDecl
+  // CHECK-NEXT: CompoundStmt
+#pragma acc kernels loop if( j < f)
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}kernels loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' <IntegralToFloating>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'int' lvalue ParmVar{{.*}} 'j' 'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'float' lvalue ParmVar{{.*}} 'f' 'float'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+}
+
+template<typename T>
+void TemplFunc() {
+  // CHECK: FunctionTemplateDecl{{.*}}TemplFunc
+  // CHECK-NEXT: TemplateTypeParmDecl
+
+  // Match the prototype:
+  // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc parallel loop if(T::SomeFloat < typename T::IntTy{})
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}parallel loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '<'
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'typename T::IntTy' 'typename T::IntTy'
+  // CHECK-NEXT: InitListExpr{{.*}} 'void'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+#pragma acc serial loop if(typename T::IntTy{})
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}serial loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'typename T::IntTy' 'typename T::IntTy'
+  // CHECK-NEXT: InitListExpr{{.*}} 'void'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+#pragma acc kernels loop if(T::SomeFloat)
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}kernels loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+#pragma acc parallel loop if(T::BC)
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}parallel loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // Match the instantiation:
+  // CHECK: FunctionDecl{{.*}}TemplFunc{{.*}}implicit_instantiation
+  // CHECK-NEXT: TemplateArgument type 'InstTy'
+  // CHECK-NEXT: RecordType{{.*}} 'InstTy'
+  // CHECK-NEXT: CXXRecord{{.*}} 'InstTy'
+  // CHECK-NEXT: CompoundStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}parallel loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' <IntegralToFloating>
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename InstTy::IntTy':'int' functional cast to typename struct InstTy::IntTy <NoOp>
+  // CHECK-NEXT: InitListExpr {{.*}}'typename InstTy::IntTy':'int'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}serial loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <IntegralToBoolean>
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename InstTy::IntTy':'int' functional cast to typename struct InstTy::IntTy <NoOp>
+  // CHECK-NEXT: InitListExpr {{.*}}'typename InstTy::IntTy':'int'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}kernels loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}parallel loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'bool' <UserDefinedConversion>
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'bool'
+  // CHECK-NEXT: MemberExpr{{.*}} .operator bool
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const BoolConversion' lvalue Var{{.*}} 'BC' 'const BoolConversion'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+}
+
+struct BoolConversion{ operator bool() const;};
+struct InstTy {
+  using IntTy = int;
+  static constexpr float SomeFloat = 5.0;
+  static constexpr BoolConversion BC;
+};
+
+void Instantiate() {
+  TemplFunc<InstTy>();
+}
+#endif

diff  --git a/clang/test/SemaOpenACC/combined-construct-if-clause.c b/clang/test/SemaOpenACC/combined-construct-if-clause.c
new file mode 100644
index 00000000000000..563f1cd25377bd
--- /dev/null
+++ b/clang/test/SemaOpenACC/combined-construct-if-clause.c
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+void BoolExpr(int *I, float *F) {
+
+  typedef struct {} SomeStruct;
+  int Array[5];
+
+  struct C{};
+  // expected-error at +1{{expected expression}}
+#pragma acc parallel loop if (struct C f())
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{unexpected type name 'SomeStruct': expected expression}}
+#pragma acc serial loop if (SomeStruct)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{unexpected type name 'SomeStruct': expected expression}}
+#pragma acc serial loop if (SomeStruct())
+  for (unsigned i = 0; i < 5; ++i);
+
+  SomeStruct S;
+  // expected-error at +1{{statement requires expression of scalar type ('SomeStruct' invalid)}}
+#pragma acc serial loop if (S)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +1{{address of array 'Array' will always evaluate to 'true'}}
+#pragma acc kernels loop if (Array)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +4{{incompatible pointer types assigning to 'int *' from 'float *'}}
+  // expected-warning at +3{{using the result of an assignment as a condition without parentheses}}
+  // expected-note at +2{{place parentheses around the assignment to silence this warning}}
+  // expected-note at +1{{use '==' to turn this assignment into an equality comparison}}
+#pragma acc kernels loop if (I = F)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc parallel loop if (I)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc serial loop if (F)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc kernels loop if (*I < *F)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'data' not yet implemented}}
+  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
+#pragma acc data if (*I < *F)
+  for (unsigned i = 0; i < 5; ++i);
+#pragma acc parallel loop if (*I < *F)
+  for(int i = 0; i < 5; ++i);
+#pragma acc serial loop if (*I < *F)
+  for(int i = 0; i < 5; ++i);
+#pragma acc kernels loop if (*I < *F)
+  for(int i = 0; i < 5; ++i);
+
+  // expected-error at +1{{OpenACC 'if' clause is not valid on 'loop' directive}}
+#pragma acc loop if(I)
+  for(int i = 5; i < 10;++i);
+}

diff  --git a/clang/test/SemaOpenACC/combined-construct-if-clause.cpp b/clang/test/SemaOpenACC/combined-construct-if-clause.cpp
new file mode 100644
index 00000000000000..cf1bdadd4c8921
--- /dev/null
+++ b/clang/test/SemaOpenACC/combined-construct-if-clause.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+struct NoBoolConversion{};
+struct BoolConversion{
+  operator bool();
+};
+
+template <typename T, typename U>
+void BoolExpr() {
+
+  // expected-error at +1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
+#pragma acc parallel loop if (NoBoolConversion{})
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +2{{no member named 'NotValid' in 'NoBoolConversion'}}
+  // expected-note@#INST{{in instantiation of function template specialization}}
+#pragma acc serial loop if (T::NotValid)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc kernels loop if (BoolConversion{})
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
+#pragma acc serial loop if (T{})
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc parallel loop if (U{})
+  for (unsigned i = 0; i < 5; ++i);
+}
+
+void Instantiate() {
+  BoolExpr<NoBoolConversion, BoolConversion>(); // #INST
+}

diff  --git a/clang/test/SemaOpenACC/combined-construct-self-ast.cpp b/clang/test/SemaOpenACC/combined-construct-self-ast.cpp
new file mode 100644
index 00000000000000..3a6ba3ca6aea23
--- /dev/null
+++ b/clang/test/SemaOpenACC/combined-construct-self-ast.cpp
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s
+
+// Test this with PCH.
+// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s
+// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s
+
+#ifndef PCH_HELPER
+#define PCH_HELPER
+
+template<typename T>
+void TemplFunc() {
+  // CHECK: FunctionTemplateDecl{{.*}}TemplFunc
+  // CHECK-NEXT: TemplateTypeParmDecl
+
+  // Match the prototype:
+  // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc serial loop self
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}serial loop
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+#pragma acc kernels loop self(T::SomeFloat)
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}kernels loop
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+#pragma acc parallel loop self(T::SomeFloat) if (T::SomeFloat)
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}parallel loop
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+#pragma acc serial loop if(T::SomeFloat) self(T::SomeFloat)
+  for (unsigned i = 0; i < 5; ++i);
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}serial loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+  //
+  // Match the instantiation:
+  // CHECK: FunctionDecl{{.*}}TemplFunc{{.*}}implicit_instantiation
+  // CHECK-NEXT: TemplateArgument type 'InstTy'
+  // CHECK-NEXT: RecordType{{.*}} 'InstTy'
+  // CHECK-NEXT: CXXRecord{{.*}} 'InstTy'
+  // CHECK-NEXT: CompoundStmt
+  //
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}serial loop
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}kernels loop
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}parallel loop
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+  // CHECK-NEXT: OpenACCCombinedConstruct{{.*}}serial loop
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: self clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
+  // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
+  // CHECK-NEXT: ForStmt
+  // CHECK: NullStmt
+
+}
+
+struct BoolConversion{ operator bool() const;};
+struct InstTy {
+  using IntTy = int;
+  static constexpr float SomeFloat = 5.0;
+  static constexpr BoolConversion BC;
+};
+
+void Instantiate() {
+  TemplFunc<InstTy>();
+}
+#endif

diff  --git a/clang/test/SemaOpenACC/combined-construct-self-clause.c b/clang/test/SemaOpenACC/combined-construct-self-clause.c
new file mode 100644
index 00000000000000..39ad85eaf2e99c
--- /dev/null
+++ b/clang/test/SemaOpenACC/combined-construct-self-clause.c
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+void BoolExpr(int *I, float *F) {
+  typedef struct {} SomeStruct;
+  struct C{};
+  // expected-error at +1{{expected expression}}
+#pragma acc parallel loop self (struct C f())
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{unexpected type name 'SomeStruct': expected expression}}
+#pragma acc serial loop self (SomeStruct)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{unexpected type name 'SomeStruct': expected expression}}
+#pragma acc kernels loop self (SomeStruct())
+  for (unsigned i = 0; i < 5; ++i);
+
+  SomeStruct S;
+  // expected-error at +1{{statement requires expression of scalar type ('SomeStruct' invalid)}}
+#pragma acc parallel loop self (S)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc parallel loop self (I)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc serial loop self (F)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc kernels loop self (*I < *F)
+  for (unsigned i = 0; i < 5; ++i);
+}
+
+void WarnMaybeNotUsed(int val1, int val2) {
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop self if(val1)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc serial loop self(val1) if(val1)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc kernels loop if(val1) self
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop if(val1) self(val2)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // The below don't warn because one side or the other has an error, thus is
+  // not added to the AST.
+
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
+#pragma acc serial loop self if(invalid)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
+#pragma acc kernels loop self(invalid) if(val1)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +2{{expected expression}}
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
+#pragma acc parallel loop self() if(invalid)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
+#pragma acc serial loop if(invalid) self
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
+#pragma acc kernels loop if(val2) self(invalid)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
+#pragma acc parallel loop if(invalid) self(val1)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{OpenACC 'self' clause is not valid on 'loop' directive}}
+#pragma acc loop self
+  for(int i = 5; i < 10;++i);
+}

diff  --git a/clang/test/SemaOpenACC/combined-construct-self-clause.cpp b/clang/test/SemaOpenACC/combined-construct-self-clause.cpp
new file mode 100644
index 00000000000000..73f5a55d77c31b
--- /dev/null
+++ b/clang/test/SemaOpenACC/combined-construct-self-clause.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+struct NoBoolConversion{};
+struct BoolConversion{
+  operator bool();
+};
+
+template <typename T, typename U>
+void BoolExpr() {
+  // expected-error at +1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
+#pragma acc parallel loop self (NoBoolConversion{})
+  for (unsigned i = 0; i < 5; ++i);
+  // expected-error at +2{{no member named 'NotValid' in 'NoBoolConversion'}}
+  // expected-note@#INST{{in instantiation of function template specialization}}
+#pragma acc serial loop self (T::NotValid)
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc kernels loop self (BoolConversion{})
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
+#pragma acc parallel loop self (T{})
+  for (unsigned i = 0; i < 5; ++i);
+
+#pragma acc parallel loop self (U{})
+  for (unsigned i = 0; i < 5; ++i);
+}
+
+struct HasBool {
+  static constexpr bool B = true;
+};
+
+template<typename T>
+void WarnMaybeNotUsed() {
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop self if(T::B)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc kernels loop self(T::B) if(T::B)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc serial loop if(T::B) self
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop if(T::B) self(T::B)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // We still warn in the cases of dependent failures, since the diagnostic
+  // happens immediately rather than during instantiation.
+
+  // expected-error at +4{{no member named 'Invalid' in 'HasBool'}}
+  // expected-note@#NOT_USED_INST{{in instantiation of function template specialization 'WarnMaybeNotUsed<HasBool>' requested here}}
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop self if(T::Invalid)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +3{{no member named 'Invalid' in 'HasBool'}}
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc serial loop self(T::Invalid) if(T::B)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +3{{no member named 'Invalid' in 'HasBool'}}
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc kernels loop self(T::B) if(T::Invalid)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +3{{no member named 'Invalid' in 'HasBool'}}
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop if(T::Invalid) self
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +3{{no member named 'Invalid' in 'HasBool'}}
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop if(T::Invalid) self(T::B)
+  for (unsigned i = 0; i < 5; ++i);
+
+  // expected-error at +3{{no member named 'Invalid' in 'HasBool'}}
+  // expected-warning at +2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
+  // expected-note at +1{{previous clause is here}}
+#pragma acc parallel loop if(T::B) self(T::Invalid)
+  for (unsigned i = 0; i < 5; ++i);
+}
+
+void Instantiate() {
+  BoolExpr<NoBoolConversion, BoolConversion>(); // #INST
+  WarnMaybeNotUsed<HasBool>(); // #NOT_USED_INST
+}

diff  --git a/clang/test/SemaOpenACC/compute-construct-default-clause.c b/clang/test/SemaOpenACC/compute-construct-default-clause.c
index 519dbc173a6724..17f1b27a9b5838 100644
--- a/clang/test/SemaOpenACC/compute-construct-default-clause.c
+++ b/clang/test/SemaOpenACC/compute-construct-default-clause.c
@@ -16,7 +16,6 @@ void SingleOnly() {
   #pragma acc kernels self default(present) present(i) default(none) copy(i)
   while(0);
 
-  // expected-warning at +5{{OpenACC clause 'self' not yet implemented}}
   // expected-warning at +4{{OpenACC clause 'default' not yet implemented}}
   // expected-warning at +3{{OpenACC clause 'private' not yet implemented}}
   // expected-warning at +2{{OpenACC clause 'default' not yet implemented}}
@@ -24,7 +23,6 @@ void SingleOnly() {
   #pragma acc parallel loop self default(present) private(i) default(none) copy(i)
   for(int i = 0; i < 5; ++i);
 
-  // expected-warning at +2{{OpenACC clause 'self' not yet implemented, clause ignored}}
   // expected-error at +1{{expected '('}}
   #pragma acc serial loop self default private(i) default(none) if(i)
   for(int i = 0; i < 5; ++i);

diff  --git a/clang/test/SemaOpenACC/compute-construct-if-clause.c b/clang/test/SemaOpenACC/compute-construct-if-clause.c
index 877c9c33cbd2ee..7cdc35275acce0 100644
--- a/clang/test/SemaOpenACC/compute-construct-if-clause.c
+++ b/clang/test/SemaOpenACC/compute-construct-if-clause.c
@@ -47,13 +47,10 @@ void BoolExpr(int *I, float *F) {
   // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc data if (*I < *F)
   while(0);
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc parallel loop if (*I < *F)
   for(int i = 0; i < 5; ++i);
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc serial loop if (*I < *F)
   for(int i = 0; i < 5; ++i);
-  // expected-warning at +1{{OpenACC clause 'if' not yet implemented}}
 #pragma acc kernels loop if (*I < *F)
   for(int i = 0; i < 5; ++i);
 


        


More information about the cfe-commits mailing list