[OpenMP] Replace predetermined shared for const variable

The following appears in OpenMP 3.1 sec. 2.9.1.1 as a predetermined
data-sharing attribute:

> Variables with const-qualified type having no mutable member are
> shared.

It does not appear in OpenmP 4.0, 4.5, or 5.0.  This patch removes the
implementation of that attribute when the requested OpenMP version is
greater than 3.1.

One effect of that removal is that `default(none)` affects const
variables without mutable members.

Also, without this patch, if a const variable without mutable members
was explicitly lastprivate or private, it was an error because it was
predetermined shared.  Now, clang instead complains that it's const
without mutable fields, which is a more intelligible diagnostic.  That
should be fine for all of the above versions because they all have
something like the following, which is quoted from OpenMP 5.0
sec. 2.19.3:

> A variable that is privatized must not have a const-qualified type
> unless it is of class type with a mutable member. This restriction does
> not apply to the firstprivate clause.

reduction and linear clauses already have separate checks for const
variables.  Future patches will merge the implementations.

Reviewed By: ABataev

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

llvm-svn: 350439
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 59c4b49..7b70225 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -1080,6 +1080,43 @@
   return false;
 }
 
+static bool isConstNotMutableType(Sema &SemaRef, ValueDecl *D,
+                                  bool *IsClassType = nullptr) {
+  ASTContext &Context = SemaRef.getASTContext();
+  QualType Type = D->getType().getNonReferenceType().getCanonicalType();
+  bool IsConstant = Type.isConstant(Context);
+  Type = Context.getBaseElementType(Type);
+  const CXXRecordDecl *RD =
+      SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
+  if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD))
+    if (const ClassTemplateDecl *CTD = CTSD->getSpecializedTemplate())
+      RD = CTD->getTemplatedDecl();
+  if (IsClassType)
+    *IsClassType = RD;
+  return IsConstant && !(SemaRef.getLangOpts().CPlusPlus && RD &&
+                         RD->hasDefinition() && RD->hasMutableFields());
+}
+
+static bool rejectConstNotMutableType(Sema &SemaRef, ValueDecl *D,
+                                      OpenMPClauseKind CKind,
+                                      SourceLocation ELoc) {
+  ASTContext &Context = SemaRef.getASTContext();
+  bool IsClassType;
+  if (isConstNotMutableType(SemaRef, D, &IsClassType)) {
+    SemaRef.Diag(ELoc, IsClassType ? diag::err_omp_const_not_mutable_variable
+                                   : diag::err_omp_const_variable)
+        << getOpenMPClauseName(CKind);
+    VarDecl *VD = dyn_cast<VarDecl>(D);
+    bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+                             VarDecl::DeclarationOnly;
+    SemaRef.Diag(D->getLocation(),
+                 IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+        << D;
+    return true;
+  }
+  return false;
+}
+
 const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
                                                    bool FromParent) {
   D = getCanonicalDecl(D);
@@ -1177,34 +1214,28 @@
     return DVar;
   }
 
-  QualType Type = D->getType().getNonReferenceType().getCanonicalType();
-  bool IsConstant = Type.isConstant(SemaRef.getASTContext());
-  Type = SemaRef.getASTContext().getBaseElementType(Type);
-  // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
-  // in a Construct, C/C++, predetermined, p.6]
-  //  Variables with const qualified type having no mutable member are
-  //  shared.
-  const CXXRecordDecl *RD =
-      SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
-  if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD))
-    if (const ClassTemplateDecl *CTD = CTSD->getSpecializedTemplate())
-      RD = CTD->getTemplatedDecl();
-  if (IsConstant &&
-      !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasDefinition() &&
-        RD->hasMutableFields())) {
-    // Variables with const-qualified type having no mutable member may be
-    // listed in a firstprivate clause, even if they are static data members.
-    DSAVarData DVarTemp = hasInnermostDSA(
-        D,
-        [](OpenMPClauseKind C) {
-          return C == OMPC_firstprivate || C == OMPC_shared;
-        },
-        MatchesAlways, FromParent);
-    if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
-      return DVarTemp;
+  // The predetermined shared attribute for const-qualified types having no
+  // mutable members was removed after OpenMP 3.1.
+  if (SemaRef.LangOpts.OpenMP <= 31) {
+    // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+    // in a Construct, C/C++, predetermined, p.6]
+    //  Variables with const qualified type having no mutable member are
+    //  shared.
+    if (isConstNotMutableType(SemaRef, D)) {
+      // Variables with const-qualified type having no mutable member may be
+      // listed in a firstprivate clause, even if they are static data members.
+      DSAVarData DVarTemp = hasInnermostDSA(
+          D,
+          [](OpenMPClauseKind C) {
+            return C == OMPC_firstprivate || C == OMPC_shared;
+          },
+          MatchesAlways, FromParent);
+      if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
+        return DVarTemp;
 
-    DVar.CKind = OMPC_shared;
-    return DVar;
+      DVar.CKind = OMPC_shared;
+      return DVar;
+    }
   }
 
   // Explicitly specified attributes and local variables with predetermined
@@ -9791,6 +9822,17 @@
       continue;
     Type = Type.getNonReferenceType();
 
+    // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
+    // A variable that is privatized must not have a const-qualified type
+    // unless it is of class type with a mutable member. This restriction does
+    // not apply to the firstprivate clause.
+    //
+    // OpenMP 3.1 [2.9.3.3, private clause, Restrictions]
+    // A variable that appears in a private clause must not have a
+    // const-qualified type unless it is of class type with a mutable member.
+    if (rejectConstNotMutableType(*this, D, OMPC_private, ELoc))
+      continue;
+
     // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
     // in a Construct]
     //  Variables with the predetermined data-sharing attributes may not be
@@ -10212,6 +10254,17 @@
       continue;
     Type = Type.getNonReferenceType();
 
+    // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
+    // A variable that is privatized must not have a const-qualified type
+    // unless it is of class type with a mutable member. This restriction does
+    // not apply to the firstprivate clause.
+    //
+    // OpenMP 3.1 [2.9.3.5, lastprivate clause, Restrictions]
+    // A variable that appears in a lastprivate clause must not have a
+    // const-qualified type unless it is of class type with a mutable member.
+    if (rejectConstNotMutableType(*this, D, OMPC_lastprivate, ELoc))
+      continue;
+
     OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
     // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
     // in a Construct]