Author: erichkeane
Date: 2025-08-04T11:42:33-07:00
New Revision: 4e0b68cef0bdf0d806cd778fbf0b7ddd80b44b4d

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

LOG: [OpenACC] Implement warning restrictions for 'firstprivate'

'firstprivate' can't be generated unless we have a copy constructor, so
this patch implements the restriction as a warning, and prevents the
item from being added to the AST.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/SemaOpenACC.h
    clang/lib/Sema/SemaOpenACC.cpp
    clang/test/SemaOpenACC/private_firstprivate_reduction_required_ops.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0ba06d6f2dee3..9ce142e7b37cc 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13531,7 +13531,8 @@ def err_acc_device_type_multiple_archs
 def warn_acc_var_referenced_lacks_op
     : Warning<"variable of type %0 referenced in OpenACC '%1' clause does not "
               "have a %enum_select<AccVarReferencedReason>{%DefCtor{default "
-              "constructor}|%Dtor{destructor}}2; reference has no effect">,
+              "constructor}|%CopyCtor{copy constructor}|%Dtor{destructor}}2; "
+              "reference has no effect">,
       InGroup<DiagGroup<"openacc-var-lacks-operation">>,
       DefaultError;
 

diff  --git a/clang/include/clang/Sema/SemaOpenACC.h 
b/clang/include/clang/Sema/SemaOpenACC.h
index f51045d26e23b..e9e4e6c2b380c 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -176,10 +176,6 @@ class SemaOpenACC : public SemaBase {
 
     void checkFor();
 
-    //  void checkRangeFor(); ?? ERICH
-    //  const ValueDecl *checkInit();
-    //  void checkCond(const ValueDecl *Init);
-    //  void checkInc(const ValueDecl *Init);
   public:
     // Checking for non-instantiation version of a Range-for.
     ForStmtBeginChecker(SemaOpenACC &SemaRef, SourceLocation ForLoc,

diff  --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 8f32817aec48f..8212646facd86 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -642,21 +642,13 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind 
CK, Expr *VarExpr,
   if (!InnerExpr || InnerExpr->isTypeDependent())
     return VarExpr;
 
-  const auto *RD = InnerExpr->getType()->getAsCXXRecordDecl();
+  auto *RD = InnerExpr->getType()->getAsCXXRecordDecl();
 
   // if this isn't a C++ record decl, we can create/copy/destroy this thing at
   // will without problem, so this is a success.
   if (!RD)
     return VarExpr;
 
-  // TODO: OpenACC:
-  // Private must have default ctor + dtor in InnerExpr
-  // FirstPrivate must have copyctor + dtor in InnerExpr
-  // Reduction must have copyctor + dtor + operation in InnerExpr
-
-  // TODO OpenACC: It isn't clear what the requirements are for default
-  // constructor/copy constructor are for First private and reduction, but
-  // private requires a default constructor.
   if (CK == OpenACCClauseKind::Private) {
     bool HasNonDeletedDefaultCtor =
         llvm::find_if(RD->ctors(), [](const CXXConstructorDecl *CD) {
@@ -669,6 +661,26 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind 
CK, Expr *VarExpr,
           << clang::diag::AccVarReferencedReason::DefCtor;
       return ExprError();
     }
+  } else if (CK == OpenACCClauseKind::FirstPrivate) {
+    if (!RD->hasSimpleCopyConstructor()) {
+      Sema::SpecialMemberOverloadResult SMOR = S.SemaRef.LookupSpecialMember(
+          RD, CXXSpecialMemberKind::CopyConstructor, /*ConstArg=*/true,
+          /*VolatileArg=*/false, /*RValueThis=*/false, /*ConstThis=*/false,
+          /*VolatileThis=*/false);
+
+      if (SMOR.getKind() != Sema::SpecialMemberOverloadResult::Success ||
+          SMOR.getMethod()->isDeleted()) {
+        S.Diag(InnerExpr->getBeginLoc(),
+               clang::diag::warn_acc_var_referenced_lacks_op)
+            << InnerExpr->getType() << CK
+            << clang::diag::AccVarReferencedReason::CopyCtor;
+        return ExprError();
+      }
+    }
+  } else if (CK == OpenACCClauseKind::Reduction) {
+    // TODO: OpenACC:
+    // Reduction must have copyctor + dtor + operation in InnerExpr I think?
+    // Need to confirm when implementing this part.
   }
 
   // All 3 things need to make sure they have a dtor.

diff  --git 
a/clang/test/SemaOpenACC/private_firstprivate_reduction_required_ops.cpp 
b/clang/test/SemaOpenACC/private_firstprivate_reduction_required_ops.cpp
index e0aee123fe754..ad3cb8ba5d3ff 100644
--- a/clang/test/SemaOpenACC/private_firstprivate_reduction_required_ops.cpp
+++ b/clang/test/SemaOpenACC/private_firstprivate_reduction_required_ops.cpp
@@ -35,6 +35,17 @@ struct ImplicitDelDtor {
   DeletedDtor d;
 };
 
+struct DeletedCopy {
+  DeletedCopy(const DeletedCopy&) = delete;
+};
+
+struct DefaultedCopy {
+  DefaultedCopy(const DefaultedCopy&) = default;
+};
+struct UserCopy {
+  UserCopy(const UserCopy&);
+};
+
 void private_uses(ImplicitCtorDtor &CDT, ImplDeletedCtor &IDC,
                   DefaultedCtor &DefC, ImpledCtor &IC, DeletedCtor &DelC,
                   ImpledDtor &ID, DefaultedDtor &DefD, DeletedDtor &DelD,
@@ -101,3 +112,78 @@ void inst(ImplicitCtorDtor &CDT, ImplDeletedCtor &IDC,
   // expected-note@+1{{in instantiation}}
   private_templ(IDD);
 }
+
+void firstprivate_uses(ImplicitCtorDtor &CDT, ImplDeletedCtor &IDC,
+                  DefaultedCtor &DefC, ImpledCtor &IC, DeletedCtor &DelC,
+                  ImpledDtor &ID, DefaultedDtor &DefD, DeletedDtor &DelD,
+                  ImplicitDelDtor &IDD, DeletedCopy &DelCopy,
+                  DefaultedCopy &DefCopy, UserCopy &UDCopy) {
+#pragma acc parallel firstprivate(CDT)
+  ;
+
+#pragma acc parallel firstprivate(IDC)
+  ;
+
+#pragma acc parallel firstprivate(DefC)
+  ;
+
+#pragma acc parallel firstprivate(IC)
+  ;
+
+#pragma acc parallel firstprivate(DelC)
+  ;
+
+#pragma acc parallel firstprivate(ID)
+  ;
+
+#pragma acc parallel firstprivate(DefD)
+  ;
+
+  // expected-error@+1{{variable of type 'DeletedDtor' referenced in OpenACC 
'firstprivate' clause does not have a destructor; reference has no effect}}
+#pragma acc parallel firstprivate(DelD)
+  ;
+
+  // expected-error@+1{{variable of type 'ImplicitDelDtor' referenced in 
OpenACC 'firstprivate' clause does not have a copy constructor; reference has 
no effect}}
+#pragma acc parallel firstprivate(IDD)
+  ;
+
+  // expected-error@+1{{variable of type 'DeletedCopy' referenced in OpenACC 
'firstprivate' clause does not have a copy constructor; reference has no 
effect}}
+#pragma acc parallel firstprivate(DelCopy)
+  ;
+#pragma acc parallel firstprivate(DefCopy)
+  ;
+#pragma acc parallel firstprivate(UDCopy)
+  ;
+}
+
+template<typename T>
+void firstprivate_template(T& t) {
+#pragma acc parallel firstprivate(t) // #FIRSTPRIV
+  ;
+}
+
+void firstprivate_inst(ImplicitCtorDtor &CDT, ImplDeletedCtor &IDC,
+                       DefaultedCtor &DefC, ImpledCtor &IC, DeletedCtor &DelC,
+                       ImpledDtor &ID, DefaultedDtor &DefD, DeletedDtor &DelD,
+                       ImplicitDelDtor &IDD, DeletedCopy &DelCopy,
+                       DefaultedCopy &DefCopy, UserCopy &UDCopy) {
+  firstprivate_template(CDT);
+  firstprivate_template(IDC);
+  firstprivate_template(DefC);
+  firstprivate_template(IC);
+  firstprivate_template(DelC);
+  firstprivate_template(ID);
+  firstprivate_template(DefD);
+  // expected-error@#FIRSTPRIV{{variable of type 'DeletedDtor' referenced in 
OpenACC 'firstprivate' clause does not have a destructor; reference has no 
effect}}
+  // expected-note@+1{{in instantiation}}
+  firstprivate_template(DelD);
+  // expected-error@#FIRSTPRIV{{variable of type 'ImplicitDelDtor' referenced 
in OpenACC 'firstprivate' clause does not have a copy constructor; reference 
has no effect}}
+  // expected-note@+1{{in instantiation}}
+  firstprivate_template(IDD);
+  // expected-error@#FIRSTPRIV{{variable of type 'DeletedCopy' referenced in 
OpenACC 'firstprivate' clause does not have a copy constructor; reference has 
no effect}}
+  // expected-note@+1{{in instantiation}}
+  firstprivate_template(DelCopy);
+  firstprivate_template(DefCopy);
+  firstprivate_template(UDCopy);
+}
+


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to