Skip to content

Commit 22994ed

Browse files
authored
[OpenACC][Sema] Implement warning for non-effective 'private' (#149004)
A 'private' variable reference needs to have a default constructor and a destructor, else we cannot properly emit them in codegen. This patch adds a warning-as-default-error to diagnose this. We'll have to do something similar for firstprivate/reduction, however it isn't clear whether we could skip the check for default-constructor for those two (they still need a destructor!). Depending on how we intend to create them (and we probably have to figure this out?), we could either require JUST a copy-constructor (then make the init section just the alloca, and the copy-ctor be the 'copy' section), OR they require a default-constructor + copy-assignment.
1 parent 560e7df commit 22994ed

File tree

3 files changed

+174
-5
lines changed

3 files changed

+174
-5
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13489,6 +13489,12 @@ def err_acc_invalid_default_type
1348913489
def err_acc_device_type_multiple_archs
1349013490
: Error<"OpenACC 'device_type' clause on a 'set' construct only permits "
1349113491
"one architecture">;
13492+
def warn_acc_var_referenced_lacks_op
13493+
: Warning<"variable of type %0 referenced in OpenACC '%1' clause does not "
13494+
"have a %enum_select<AccVarReferencedReason>{%DefCtor{default "
13495+
"constructor}|%Dtor{destructor}}2; reference has no effect">,
13496+
InGroup<DiagGroup<"openacc-var-lacks-operation">>,
13497+
DefaultError;
1349213498

1349313499
// AMDGCN builtins diagnostics
1349413500
def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">;

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,66 @@ void SemaOpenACC::CheckDeclReference(SourceLocation Loc, Expr *E, Decl *D) {
624624
// loop (or we aren't in a loop!) so skip the diagnostic.
625625
}
626626

627+
namespace {
628+
// Check whether the type of the thing we are referencing is OK for things like
629+
// private, firstprivate, and reduction, which require certain operators to be
630+
// available.
631+
ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr,
632+
Expr *InnerExpr) {
633+
// There is nothing to do here, only these three have these sorts of
634+
// restrictions.
635+
if (CK != OpenACCClauseKind::Private &&
636+
CK != OpenACCClauseKind::FirstPrivate &&
637+
CK != OpenACCClauseKind::Reduction)
638+
return VarExpr;
639+
640+
// We can't test this if it isn't here, or if the type isn't clear yet.
641+
if (!InnerExpr || InnerExpr->isTypeDependent())
642+
return VarExpr;
643+
644+
const auto *RD = InnerExpr->getType()->getAsCXXRecordDecl();
645+
646+
// if this isn't a C++ record decl, we can create/copy/destroy this thing at
647+
// will without problem, so this is a success.
648+
if (!RD)
649+
return VarExpr;
650+
651+
// TODO: OpenACC:
652+
// Private must have default ctor + dtor in InnerExpr
653+
// FirstPrivate must have copyctor + dtor in InnerExpr
654+
// Reduction must have copyctor + dtor + operation in InnerExpr
655+
656+
// TODO OpenACC: It isn't clear what the requirements are for default
657+
// constructor/copy constructor are for First private and reduction, but
658+
// private requires a default constructor.
659+
if (CK == OpenACCClauseKind::Private) {
660+
bool HasNonDeletedDefaultCtor =
661+
llvm::find_if(RD->ctors(), [](const CXXConstructorDecl *CD) {
662+
return CD->isDefaultConstructor() && !CD->isDeleted();
663+
}) != RD->ctors().end();
664+
if (!HasNonDeletedDefaultCtor && !RD->needsImplicitDefaultConstructor()) {
665+
S.Diag(InnerExpr->getBeginLoc(),
666+
clang::diag::warn_acc_var_referenced_lacks_op)
667+
<< InnerExpr->getType() << CK
668+
<< clang::diag::AccVarReferencedReason::DefCtor;
669+
return ExprError();
670+
}
671+
}
672+
673+
// All 3 things need to make sure they have a dtor.
674+
bool DestructorDeleted =
675+
RD->getDestructor() && RD->getDestructor()->isDeleted();
676+
if (DestructorDeleted && !RD->needsImplicitDestructor()) {
677+
S.Diag(InnerExpr->getBeginLoc(),
678+
clang::diag::warn_acc_var_referenced_lacks_op)
679+
<< InnerExpr->getType() << CK
680+
<< clang::diag::AccVarReferencedReason::Dtor;
681+
return ExprError();
682+
}
683+
return VarExpr;
684+
}
685+
} // namespace
686+
627687
ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
628688
Expr *VarExpr) {
629689
// This has unique enough restrictions that we should split it to a separate
@@ -660,7 +720,7 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
660720
if (const auto *DRE = dyn_cast<DeclRefExpr>(CurVarExpr)) {
661721
if (isa<VarDecl, NonTypeTemplateParmDecl>(
662722
DRE->getFoundDecl()->getCanonicalDecl()))
663-
return VarExpr;
723+
return CheckVarType(*this, CK, VarExpr, CurVarExpr);
664724
}
665725

666726
// If CK is a Reduction, this special cases for OpenACC3.3 2.5.15: "A var in a
@@ -679,9 +739,9 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
679739
// declare, reduction, and use_device.
680740
const auto *This = dyn_cast<CXXThisExpr>(ME->getBase());
681741
if (This && This->isImplicit())
682-
return VarExpr;
742+
return CheckVarType(*this, CK, VarExpr, CurVarExpr);
683743
} else {
684-
return VarExpr;
744+
return CheckVarType(*this, CK, VarExpr, CurVarExpr);
685745
}
686746
}
687747
}
@@ -690,14 +750,14 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
690750
// doesn't fall into 'variable or array name'
691751
if (CK != OpenACCClauseKind::UseDevice &&
692752
DK != OpenACCDirectiveKind::Declare && isa<CXXThisExpr>(CurVarExpr))
693-
return VarExpr;
753+
return CheckVarType(*this, CK, VarExpr, CurVarExpr);
694754

695755
// Nothing really we can do here, as these are dependent. So just return they
696756
// are valid.
697757
if (isa<DependentScopeDeclRefExpr>(CurVarExpr) ||
698758
(CK != OpenACCClauseKind::Reduction &&
699759
isa<CXXDependentScopeMemberExpr>(CurVarExpr)))
700-
return VarExpr;
760+
return CheckVarType(*this, CK, VarExpr, CurVarExpr);
701761

702762
// There isn't really anything we can do in the case of a recovery expr, so
703763
// skip the diagnostic rather than produce a confusing diagnostic.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// RUN: %clang_cc1 %s -fopenacc -verify
2+
3+
struct ImplicitCtorDtor{};
4+
5+
struct ImplDeletedCtor{
6+
ImplDeletedCtor(int i);
7+
};
8+
9+
struct DefaultedCtor {
10+
DefaultedCtor() = default;
11+
};
12+
13+
struct ImpledCtor {
14+
ImpledCtor() = default;
15+
};
16+
17+
18+
struct DeletedCtor {
19+
DeletedCtor() = delete;
20+
};
21+
22+
struct ImpledDtor {
23+
~ImpledDtor();
24+
};
25+
26+
struct DefaultedDtor {
27+
~DefaultedDtor() = default;
28+
};
29+
30+
struct DeletedDtor {
31+
~DeletedDtor() = delete;
32+
};
33+
34+
struct ImplicitDelDtor {
35+
DeletedDtor d;
36+
};
37+
38+
void private_uses(ImplicitCtorDtor &CDT, ImplDeletedCtor &IDC,
39+
DefaultedCtor &DefC, ImpledCtor &IC, DeletedCtor &DelC,
40+
ImpledDtor &ID, DefaultedDtor &DefD, DeletedDtor &DelD,
41+
ImplicitDelDtor &IDD) {
42+
43+
#pragma acc parallel private(CDT)
44+
;
45+
46+
// expected-error@+1{{variable of type 'ImplDeletedCtor' referenced in OpenACC 'private' clause does not have a default constructor; reference has no effect}}
47+
#pragma acc parallel private(IDC)
48+
;
49+
50+
#pragma acc parallel private(DefC)
51+
;
52+
53+
#pragma acc parallel private(IC)
54+
;
55+
56+
// expected-error@+1{{variable of type 'DeletedCtor' referenced in OpenACC 'private' clause does not have a default constructor; reference has no effect}}
57+
#pragma acc parallel private(DelC)
58+
;
59+
60+
#pragma acc parallel private(ID)
61+
;
62+
63+
#pragma acc parallel private(DefD)
64+
;
65+
66+
// expected-error@+1{{variable of type 'DeletedDtor' referenced in OpenACC 'private' clause does not have a destructor; reference has no effect}}
67+
#pragma acc parallel private(DelD)
68+
;
69+
70+
// expected-error@+1{{variable of type 'ImplicitDelDtor' referenced in OpenACC 'private' clause does not have a destructor; reference has no effect}}
71+
#pragma acc parallel private(IDD)
72+
;
73+
74+
}
75+
76+
template<typename T>
77+
void private_templ(T& t) {
78+
#pragma acc parallel private(t) // #PRIV
79+
;
80+
}
81+
82+
void inst(ImplicitCtorDtor &CDT, ImplDeletedCtor &IDC,
83+
DefaultedCtor &DefC, ImpledCtor &IC, DeletedCtor &DelC,
84+
ImpledDtor &ID, DefaultedDtor &DefD, DeletedDtor &DelD,
85+
ImplicitDelDtor &IDD) {
86+
private_templ(CDT);
87+
// expected-error@#PRIV{{variable of type 'ImplDeletedCtor' referenced in OpenACC 'private' clause does not have a default constructor; reference has no effect}}
88+
// expected-note@+1{{in instantiation}}
89+
private_templ(IDC);
90+
private_templ(DefC);
91+
private_templ(IC);
92+
// expected-error@#PRIV{{variable of type 'DeletedCtor' referenced in OpenACC 'private' clause does not have a default constructor; reference has no effect}}
93+
// expected-note@+1{{in instantiation}}
94+
private_templ(DelC);
95+
private_templ(ID);
96+
private_templ(DefD);
97+
// expected-error@#PRIV{{variable of type 'DeletedDtor' referenced in OpenACC 'private' clause does not have a destructor; reference has no effect}}
98+
// expected-note@+1{{in instantiation}}
99+
private_templ(DelD);
100+
// expected-error@#PRIV{{variable of type 'ImplicitDelDtor' referenced in OpenACC 'private' clause does not have a destructor; reference has no effect}}
101+
// expected-note@+1{{in instantiation}}
102+
private_templ(IDD);
103+
}

0 commit comments

Comments
 (0)