Skip to content

Commit

Permalink
[OpenMP] Replace predetermined shared for const variable
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jdenny-ornl committed Jan 4, 2019
1 parent 79d4851 commit e6234d1
Show file tree
Hide file tree
Showing 40 changed files with 439 additions and 376 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -8778,6 +8778,8 @@ def err_omp_required_access : Error<
"%0 variable must be %1">;
def err_omp_const_variable : Error<
"const-qualified variable cannot be %0">;
def err_omp_const_not_mutable_variable : Error<
"const-qualified variable without mutable fields cannot be %0">;
def err_omp_const_reduction_list_item : Error<
"const-qualified list item cannot be reduction">;
def err_omp_linear_incomplete_type : Error<
Expand Down
107 changes: 80 additions & 27 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,43 @@ bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const {
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);
Expand Down Expand Up @@ -1177,34 +1214,28 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
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
Expand Down Expand Up @@ -9791,6 +9822,17 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
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
Expand Down Expand Up @@ -10212,6 +10254,17 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
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]
Expand Down
20 changes: 10 additions & 10 deletions clang/test/OpenMP/distribute_parallel_for_lastprivate_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class S2 {
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc; // expected-note {{static data member is predetermined as shared}}
static const float S2sc; // expected-note {{'S2sc' declared here}}
};
const float S2::S2sc = 0;
const S2 b;
Expand All @@ -33,9 +33,9 @@ class S3 {
S3() : a(0) {}
S3(S3 &s3) : a(s3.a) {}
};
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
const S3 c; // expected-note {{'c' defined here}}
const S3 ca[5]; // expected-note {{'ca' defined here}}
extern const int f; // expected-note {{'f' declared here}}
class S4 {
int a;
S4(); // expected-note 3 {{implicitly declared private here}}
Expand Down Expand Up @@ -171,8 +171,8 @@ using A::x;
}

int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
const int d = 5; // expected-note {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
S4 e(4);
S5 g(5);
S3 m;
Expand Down Expand Up @@ -221,7 +221,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}} expected-error {{incomplete type 'S1' where a complete type is required}} expected-warning {{Non-trivial type 'const S2' is mapped, only trivial types are guaranteed to be mapped correctly}} expected-warning {{Non-trivial type 'const S3' is mapped, only trivial types are guaranteed to be mapped correctly}}
#pragma omp distribute parallel for lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 1 {{const-qualified variable without mutable fields cannot be lastprivate}} expected-error 2 {{const-qualified variable cannot be lastprivate}} expected-error {{incomplete type 'S1' where a complete type is required}} expected-warning {{Non-trivial type 'const S2' is mapped, only trivial types are guaranteed to be mapped correctly}} expected-warning {{Non-trivial type 'const S3' is mapped, only trivial types are guaranteed to be mapped correctly}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp target
Expand All @@ -241,12 +241,12 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}} expected-warning {{Non-trivial type 'const S3 [5]' is mapped, only trivial types are guaranteed to be mapped correctly}}
#pragma omp distribute parallel for lastprivate(ca) // expected-error {{const-qualified variable without mutable fields cannot be lastprivate}} expected-warning {{Non-trivial type 'const S3 [5]' is mapped, only trivial types are guaranteed to be mapped correctly}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
#pragma omp distribute parallel for lastprivate(da) // expected-error {{const-qualified variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
int xa;
Expand All @@ -262,7 +262,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
#pragma omp distribute parallel for lastprivate(S2::S2sc) // expected-error {{const-qualified variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp target
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class S2 {
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc; // expected-note {{static data member is predetermined as shared}}
static const float S2sc; // expected-note {{'S2sc' declared here}}
};
const float S2::S2sc = 0;
const S2 b;
Expand All @@ -33,9 +33,9 @@ class S3 {
S3() : a(0) {}
S3(S3 &s3) : a(s3.a) {}
};
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
const S3 c; // expected-note {{'c' defined here}}
const S3 ca[5]; // expected-note {{'ca' defined here}}
extern const int f; // expected-note {{'f' declared here}}
class S4 {
int a;
S4(); // expected-note 3 {{implicitly declared private here}}
Expand Down Expand Up @@ -171,8 +171,8 @@ using A::x;
}

int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
const int d = 5; // expected-note {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
S4 e(4);
S5 g(5);
S3 m;
Expand Down Expand Up @@ -221,7 +221,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for simd lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}} expected-error {{incomplete type 'S1' where a complete type is required}}
#pragma omp distribute parallel for simd lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 1 {{const-qualified variable without mutable fields cannot be lastprivate}} expected-error 2 {{const-qualified variable cannot be lastprivate}} expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp target
Expand All @@ -241,12 +241,12 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
#pragma omp distribute parallel for simd lastprivate(ca) // expected-error {{const-qualified variable without mutable fields cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
#pragma omp distribute parallel for simd lastprivate(da) // expected-error {{const-qualified variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
int xa;
Expand All @@ -262,7 +262,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
#pragma omp distribute parallel for simd lastprivate(S2::S2sc) // expected-error {{const-qualified variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp target
Expand Down
16 changes: 8 additions & 8 deletions clang/test/OpenMP/distribute_private_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class S3 {
public:
S3():a(0) { }
};
const S3 c; // expected-note {{predetermined as shared}}
const S3 ca[5]; // expected-note {{predetermined as shared}}
extern const int f; // expected-note {{predetermined as shared}}
const S3 c; // expected-note {{'c' defined here}}
const S3 ca[5]; // expected-note {{'ca' defined here}}
extern const int f; // expected-note {{'f' declared here}}
class S4 {
int a;
S4(); // expected-note {{implicitly declared private here}}
Expand All @@ -45,8 +45,8 @@ S3 h;


int main(int argc, char **argv) {
const int d = 5; // expected-note {{predetermined as shared}}
const int da[5] = { 0 }; // expected-note {{predetermined as shared}}
const int d = 5; // expected-note {{'d' defined here}}
const int da[5] = { 0 }; // expected-note {{'da' defined here}}
S4 e(4);
S5 g(5);
int i;
Expand All @@ -67,15 +67,15 @@ int main(int argc, char **argv) {
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private (S1) // expected-error {{'S1' does not refer to a value}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}}
#pragma omp distribute private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 1 {{const-qualified variable without mutable fields cannot be private}} expected-error 2 {{const-qualified variable cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private (argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private(ba)
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp distribute private(ca) // expected-error {{const-qualified variable without mutable fields cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private(da) // expected-error {{shared variable cannot be private}}
#pragma omp distribute private(da) // expected-error {{const-qualified variable cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp distribute private(S2::S2s) // expected-error {{shared variable cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
Expand Down
Loading

0 comments on commit e6234d1

Please sign in to comment.