[OPENMP] Parsing and sema analysis for 'copyprivate' clause.

llvm-svn: 211886
This commit is contained in:
Alexey Bataev 2014-06-27 10:37:06 +00:00
parent 8f1f87c734
commit bae9a793fd
18 changed files with 525 additions and 51 deletions

View File

@ -2433,6 +2433,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
return true;
}
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {

View File

@ -1218,6 +1218,66 @@ public:
}
};
/// \brief This represents clause 'copyprivate' in the '#pragma omp ...'
/// directives.
///
/// \code
/// #pragma omp single copyprivate(a,b)
/// \endcode
/// In this example directive '#pragma omp single' has clause 'copyprivate'
/// with the variables 'a' and 'b'.
///
class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param N Number of the variables in the clause.
///
OMPCopyprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned N)
: OMPVarListClause<OMPCopyprivateClause>(OMPC_copyprivate, StartLoc,
LParenLoc, EndLoc, N) {}
/// \brief Build an empty clause.
///
/// \param N Number of variables.
///
explicit OMPCopyprivateClause(unsigned N)
: OMPVarListClause<OMPCopyprivateClause>(
OMPC_copyprivate, SourceLocation(), SourceLocation(),
SourceLocation(), N) {}
public:
/// \brief Creates clause with a list of variables \a VL.
///
/// \param C AST context.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
///
static OMPCopyprivateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL);
/// \brief Creates an empty clause with \a N variables.
///
/// \param C AST context.
/// \param N The number of variables.
///
static OMPCopyprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
}
static bool classof(const OMPClause *T) {
return T->getClauseKind() == OMPC_copyprivate;
}
};
} // end namespace clang
#endif

View File

@ -2455,6 +2455,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
return true;
}
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {

View File

@ -7026,6 +7026,8 @@ def note_omp_predetermined_dsa : Note<
"global variable is predetermined as shared|"
"variable with automatic storage duration is predetermined as private}0"
"%select{|; perhaps you forget to enclose 'omp %2' directive into a parallel or another task region?}1">;
def note_omp_implicit_dsa : Note<
"implicitly determined as %0">;
def err_omp_loop_var_dsa : Error<
"loop iteration variable may not be %0">;
def err_omp_not_for : Error<

View File

@ -67,6 +67,7 @@ OPENMP_CLAUSE(reduction, OMPReductionClause)
OPENMP_CLAUSE(linear, OMPLinearClause)
OPENMP_CLAUSE(aligned, OMPAlignedClause)
OPENMP_CLAUSE(copyin, OMPCopyinClause)
OPENMP_CLAUSE(copyprivate, OMPCopyprivateClause)
OPENMP_CLAUSE(proc_bind, OMPProcBindClause)
OPENMP_CLAUSE(schedule, OMPScheduleClause)
OPENMP_CLAUSE(ordered, OMPOrderedClause)
@ -111,6 +112,7 @@ OPENMP_SECTIONS_CLAUSE(nowait)
// TODO more clauses allowed for directive 'omp single'.
OPENMP_SINGLE_CLAUSE(private)
OPENMP_SINGLE_CLAUSE(firstprivate)
OPENMP_SINGLE_CLAUSE(copyprivate)
OPENMP_SINGLE_CLAUSE(nowait)
// Static attributes for 'default' clause.

View File

@ -7279,8 +7279,8 @@ public:
Expr *Op);
/// \brief Called on start of new data sharing attribute block.
void StartOpenMPDSABlock(OpenMPDirectiveKind K,
const DeclarationNameInfo &DirName,
Scope *CurScope);
const DeclarationNameInfo &DirName, Scope *CurScope,
SourceLocation Loc);
/// \brief Called on end of data sharing attribute block.
void EndOpenMPDSABlock(Stmt *CurDirective);
@ -7300,8 +7300,7 @@ public:
ArrayRef<Expr *> VarList);
// brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, SourceLocation Loc,
Scope *CurScope);
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
StmtResult ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
@ -7460,6 +7459,11 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed 'copyprivate' clause.
OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {

View File

@ -1280,6 +1280,28 @@ OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPCopyinClause(N);
}
OMPCopyprivateClause *OMPCopyprivateClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
llvm::alignOf<Expr *>()) +
sizeof(Expr *) * VL.size());
OMPCopyprivateClause *Clause =
new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
return Clause;
}
OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
llvm::alignOf<Expr *>()) +
sizeof(Expr *) * N);
return new (Mem) OMPCopyprivateClause(N);
}
void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
assert(Clauses.size() == getNumClauses() &&
"Number of clauses is not the same as the preallocated buffer");

View File

@ -748,6 +748,14 @@ void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) {
}
}
void OMPClausePrinter::VisitOMPCopyprivateClause(OMPCopyprivateClause *Node) {
if (!Node->varlist_empty()) {
OS << "copyprivate";
VisitOMPClauseList(Node, '(');
OS << ")";
}
}
}
//===----------------------------------------------------------------------===//

View File

@ -335,6 +335,10 @@ void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) {
void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}
void
OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
}
}
void

View File

@ -95,6 +95,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
break;
@ -149,6 +150,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
break;
@ -193,7 +195,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
case OMPD_sections:
switch (CKind) {
#define OPENMP_SECTIONS_CLAUSE(Name) \
#define OPENMP_SECTIONS_CLAUSE(Name) \
case OMPC_##Name: \
return true;
#include "clang/Basic/OpenMPKinds.def"
@ -203,7 +205,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
case OMPD_single:
switch (CKind) {
#define OPENMP_SINGLE_CLAUSE(Name) \
#define OPENMP_SINGLE_CLAUSE(Name) \
case OMPC_##Name: \
return true;
#include "clang/Basic/OpenMPKinds.def"

View File

@ -131,7 +131,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
if (isOpenMPSimdDirective(DKind))
ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
ParseScope OMPDirectiveScope(this, ScopeFlags);
Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());
Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind = Tok.isAnnotation()
@ -159,7 +159,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
{
// The body is a block scope like in Lambdas and Blocks.
Sema::CompoundScopeRAII CompoundScope(Actions);
Actions.ActOnOpenMPRegionStart(DKind, Loc, getCurScope());
Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
Actions.ActOnStartOfCompoundStmt();
// Parse statement
AssociatedStmt = ParseStatement();
@ -269,7 +269,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// if-clause | num_threads-clause | safelen-clause | default-clause |
/// private-clause | firstprivate-clause | shared-clause | linear-clause |
/// aligned-clause | collapse-clause | lastprivate-clause |
/// reduction-clause | proc_bind-clause | schedule-clause
/// reduction-clause | proc_bind-clause | schedule-clause |
/// copyin-clause | copyprivate-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@ -345,6 +346,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
Clause = ParseOpenMPVarListClause(CKind);
break;
case OMPC_unknown:

View File

@ -68,7 +68,10 @@ public:
OpenMPDirectiveKind DKind;
OpenMPClauseKind CKind;
DeclRefExpr *RefExpr;
DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr) {}
SourceLocation ImplicitDSALoc;
DSAVarData()
: DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr),
ImplicitDSALoc() {}
};
private:
@ -83,17 +86,20 @@ private:
DeclSAMapTy SharingMap;
AlignedMapTy AlignedMap;
DefaultDataSharingAttributes DefaultAttr;
SourceLocation DefaultAttrLoc;
OpenMPDirectiveKind Directive;
DeclarationNameInfo DirectiveName;
Scope *CurScope;
SourceLocation ConstructLoc;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope)
Scope *CurScope, SourceLocation Loc)
: SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope) {
}
Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope),
ConstructLoc(Loc) {}
SharingMapTy()
: SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr) {}
Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr),
ConstructLoc() {}
};
typedef SmallVector<SharingMapTy, 64> StackTy;
@ -113,8 +119,9 @@ public:
explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {}
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope) {
Stack.push_back(SharingMapTy(DKind, DirName, CurScope));
Scope *CurScope, SourceLocation Loc) {
Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc));
Stack.back().DefaultAttrLoc = Loc;
}
void pop() {
@ -160,13 +167,22 @@ public:
}
/// \brief Set default data sharing attribute to none.
void setDefaultDSANone() { Stack.back().DefaultAttr = DSA_none; }
void setDefaultDSANone(SourceLocation Loc) {
Stack.back().DefaultAttr = DSA_none;
Stack.back().DefaultAttrLoc = Loc;
}
/// \brief Set default data sharing attribute to shared.
void setDefaultDSAShared() { Stack.back().DefaultAttr = DSA_shared; }
void setDefaultDSAShared(SourceLocation Loc) {
Stack.back().DefaultAttr = DSA_shared;
Stack.back().DefaultAttrLoc = Loc;
}
DefaultDataSharingAttributes getDefaultDSA() const {
return Stack.back().DefaultAttr;
}
SourceLocation getDefaultDSALocation() const {
return Stack.back().DefaultAttrLoc;
}
/// \brief Checks if the specified variable is a threadprivate.
bool isThreadPrivate(VarDecl *D) {
@ -176,6 +192,7 @@ public:
Scope *getCurScope() const { return Stack.back().CurScope; }
Scope *getCurScope() { return Stack.back().CurScope; }
SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
};
} // namespace
@ -227,6 +244,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
switch (Iter->DefaultAttr) {
case DSA_shared:
DVar.CKind = OMPC_shared;
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
case DSA_none:
return DVar;
@ -235,6 +253,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// in a Construct, implicitly determined, p.2]
// In a parallel construct, if no default clause is present, these
// variables are shared.
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
if (isOpenMPParallelDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
@ -456,8 +475,8 @@ void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
Scope *CurScope) {
DSAStack->push(DKind, DirName, CurScope);
Scope *CurScope, SourceLocation Loc) {
DSAStack->push(DKind, DirName, CurScope, Loc);
PushExpressionEvaluationContext(PotentiallyEvaluated);
}
@ -776,8 +795,9 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack,
PDSA_LoopIterVarLastprivate,
PDSA_ConstVarShared,
PDSA_GlobalVarShared,
PDSA_LocalVarPrivate
} Reason;
PDSA_LocalVarPrivate,
PDSA_Implicit
} Reason = PDSA_Implicit;
bool ReportHint = false;
if (IsLoopIterVar) {
if (DVar.CKind == OMPC_private)
@ -794,14 +814,18 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack,
Reason = PDSA_GlobalVarShared;
else if (VD->getType().isConstant(SemaRef.getASTContext()))
Reason = PDSA_ConstVarShared;
else {
else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) {
ReportHint = true;
Reason = PDSA_LocalVarPrivate;
}
SemaRef.Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
<< Reason << ReportHint
<< getOpenMPDirectiveName(Stack->getCurrentDirective());
if (Reason != PDSA_Implicit) {
SemaRef.Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
<< Reason << ReportHint
<< getOpenMPDirectiveName(Stack->getCurrentDirective());
} else if (DVar.ImplicitDSALoc.isValid()) {
SemaRef.Diag(DVar.ImplicitDSALoc, diag::note_omp_implicit_dsa)
<< getOpenMPClauseName(DVar.CKind);
}
}
namespace {
@ -882,8 +906,7 @@ public:
};
} // namespace
void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, SourceLocation Loc,
Scope *CurScope) {
void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
switch (DKind) {
case OMPD_parallel: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
@ -893,42 +916,48 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, SourceLocation Loc,
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params);
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_simd: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params);
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_for: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params);
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_sections: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params);
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_section: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params);
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_single: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, Params);
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_threadprivate:
@ -1695,6 +1724,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_threadprivate:
@ -1874,6 +1904,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_threadprivate:
@ -1914,10 +1945,10 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
}
switch (Kind) {
case OMPC_DEFAULT_none:
DSAStack->setDefaultDSANone();
DSAStack->setDefaultDSANone(KindKwLoc);
break;
case OMPC_DEFAULT_shared:
DSAStack->setDefaultDSAShared();
DSAStack->setDefaultDSAShared(KindKwLoc);
break;
case OMPC_DEFAULT_unknown:
llvm_unreachable("Clause kind is not allowed.");
@ -1984,6 +2015,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_threadprivate:
@ -2073,6 +2105,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_threadprivate:
@ -2126,6 +2159,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_copyprivate:
Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
@ -3281,4 +3317,108 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
continue;
}
SourceLocation ELoc = RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.14.4.1, Restrictions, p.1]
// A list item that appears in a copyin clause must be threadprivate.
DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
continue;
}
Decl *D = DE->getDecl();
VarDecl *VD = cast<VarDecl>(D);
QualType Type = VD->getType();
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
continue;
}
// OpenMP [2.14.4.2, Restrictions, p.2]
// A list item that appears in a copyprivate clause may not appear in a
// private or firstprivate clause on the single construct.
if (!DSAStack->isThreadPrivate(VD)) {
auto DVar = DSAStack->getTopDSA(VD);
if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown &&
!(DVar.CKind == OMPC_private && !DVar.RefExpr)) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_copyprivate);
ReportOriginalDSA(*this, DSAStack, VD, DVar);
continue;
}
// OpenMP [2.11.4.2, Restrictions, p.1]
// All list items that appear in a copyprivate clause must be either
// threadprivate or private in the enclosing context.
if (DVar.CKind == OMPC_unknown) {
DVar = DSAStack->getImplicitDSA(VD);
if (DVar.CKind == OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_copyprivate)
<< "threadprivate or private in the enclosing context";
ReportOriginalDSA(*this, DSAStack, VD, DVar);
continue;
}
}
}
// OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
Type = Context.getBaseElementType(Type);
CXXRecordDecl *RD =
getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
// FIXME This code must be replaced by actual assignment of the
// threadprivate variable.
if (RD) {
CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
if (MD) {
if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
MD->isDeleted()) {
Diag(ELoc, diag::err_omp_required_method)
<< getOpenMPClauseName(OMPC_copyprivate) << 2;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
MarkFunctionReferenced(ELoc, MD);
DiagnoseUseOfDecl(MD, ELoc);
}
}
// No need to mark vars as copyprivate, they are already threadprivate or
// implicitly private.
Vars.push_back(DE);
}
if (Vars.empty())
return nullptr;
return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
#undef DSAStack

View File

@ -1494,6 +1494,18 @@ public:
EndLoc);
}
/// \brief Build a new OpenMP 'copyprivate' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPCopyprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc,
EndLoc);
}
/// \brief Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@ -6403,7 +6415,8 @@ template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPParallelDirective(OMPParallelDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr);
getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr,
D->getLocStart());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
@ -6413,7 +6426,8 @@ template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPSimdDirective(OMPSimdDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, nullptr);
getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, nullptr,
D->getLocStart());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
@ -6423,7 +6437,8 @@ template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, nullptr);
getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, nullptr,
D->getLocStart());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
@ -6433,7 +6448,8 @@ template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPSectionsDirective(OMPSectionsDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr);
getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr,
D->getLocStart());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
@ -6443,7 +6459,8 @@ template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPSectionDirective(OMPSectionDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, nullptr);
getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, nullptr,
D->getLocStart());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
@ -6453,7 +6470,8 @@ template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPSingleDirective(OMPSingleDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, nullptr);
getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, nullptr,
D->getLocStart());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
@ -6680,6 +6698,21 @@ TreeTransform<Derived>::TransformOMPCopyinClause(OMPCopyinClause *C) {
C->getLParenLoc(), C->getLocEnd());
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPCopyprivateClause(OMPCopyprivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
for (auto *VE : C->varlists()) {
ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
return nullptr;
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPCopyprivateClause(
Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
}
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//

View File

@ -1724,6 +1724,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_copyin:
C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]);
break;
case OMPC_copyprivate:
C = OMPCopyprivateClause::CreateEmpty(Context, Record[Idx++]);
break;
}
Visit(C);
C->setLocStart(Reader->ReadSourceLocation(Record, Idx));
@ -1871,6 +1874,16 @@ void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) {
C->setVarRefs(Vars);
}
void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
}
//===----------------------------------------------------------------------===//
// OpenMP Directives.
//===----------------------------------------------------------------------===//

View File

@ -1782,6 +1782,13 @@ void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) {
Writer->Writer.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
}
//===----------------------------------------------------------------------===//
// OpenMP Directives.
//===----------------------------------------------------------------------===//

View File

@ -13,11 +13,11 @@ T tmain(T argc) {
T b = argc, c, d, e, f, g;
static T a;
// CHECK: static T a;
#pragma omp parallel
#pragma omp single private(argc, b), firstprivate(c, d), nowait
#pragma omp parallel private(g)
#pragma omp single private(argc, b), firstprivate(c, d), nowait copyprivate(g)
foo();
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(c,d) nowait
// CHECK-NEXT: #pragma omp parallel private(g)
// CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(c,d) nowait copyprivate(g)
// CHECK-NEXT: foo();
return T();
}
@ -26,11 +26,11 @@ int main(int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
// CHECK: static int a;
#pragma omp parallel
#pragma omp single private(argc, b), firstprivate(argv, c), nowait
#pragma omp parallel private(g)
#pragma omp single private(argc, b), firstprivate(argv, c), nowait copyprivate(g)
foo();
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(argv,c) nowait
// CHECK-NEXT: #pragma omp parallel private(g)
// CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(argv,c) nowait copyprivate(g)
// CHECK-NEXT: foo();
return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
}

View File

@ -0,0 +1,157 @@
// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
void foo() {
}
struct S1; // expected-note 2 {{declared here}}
class S2 {
mutable int a;
public:
S2() : a(0) {}
S2 &operator=(S2 &s2) { return *this; }
};
class S3 {
int a;
public:
S3() : a(0) {}
S3 &operator=(S3 &s3) { return *this; }
};
class S4 { // expected-note 2 {{'S4' declared here}}
int a;
S4();
S4 &operator=(const S4 &s4);
public:
S4(int v) : a(v) {}
};
class S5 { // expected-note 2 {{'S5' declared here}}
int a;
S5() : a(0) {}
S5 &operator=(const S5 &s5) { return *this; }
public:
S5(int v) : a(v) {}
};
S2 k;
S3 h;
S4 l(3); // expected-note 2 {{'l' defined here}}
S5 m(4); // expected-note 2 {{'m' defined here}}
#pragma omp threadprivate(h, k, l, m)
template <class T, class C>
T tmain(T argc, C **argv) {
T i;
#pragma omp parallel
#pragma omp single copyprivate // expected-error {{expected '(' after 'copyprivate'}}
#pragma omp parallel
#pragma omp single copyprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel
#pragma omp single copyprivate() // expected-error {{expected expression}}
#pragma omp parallel
#pragma omp single copyprivate(k // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel
#pragma omp single copyprivate(h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel
#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
#pragma omp parallel
#pragma omp single copyprivate(l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
#pragma omp parallel
#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel
#pragma omp single copyprivate(argv[1]) // expected-error {{expected variable name}}
#pragma omp parallel // expected-note {{implicitly determined as shared}}
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
#pragma omp parallel
#pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
foo();
#pragma omp parallel private(i)
{
#pragma omp single copyprivate(i)
foo();
}
#pragma omp parallel shared(i) // expected-note {{defined as shared}}
{
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
foo();
}
#pragma omp parallel private(i)
#pragma omp parallel default(shared) // expected-note {{implicitly determined as shared}}
{
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
foo();
}
#pragma omp parallel private(i)
#pragma omp parallel // expected-note {{implicitly determined as shared}}
{
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
foo();
}
#pragma omp parallel
#pragma omp single private(i) copyprivate(i) // expected-error {{private variable cannot be copyprivate}} expected-note {{defined as private}}
foo();
#pragma omp parallel
#pragma omp single firstprivate(i) copyprivate(i) // expected-error {{firstprivate variable cannot be copyprivate}} expected-note {{defined as firstprivate}}
foo();
return T();
}
int main(int argc, char **argv) {
int i;
#pragma omp parallel
#pragma omp single copyprivate // expected-error {{expected '(' after 'copyprivate'}}
#pragma omp parallel
#pragma omp single copyprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel
#pragma omp single copyprivate() // expected-error {{expected expression}}
#pragma omp parallel
#pragma omp single copyprivate(k // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel
#pragma omp single copyprivate(h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel
#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
#pragma omp parallel
#pragma omp single copyprivate(l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
#pragma omp parallel
#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel
#pragma omp single copyprivate(argv[1]) // expected-error {{expected variable name}}
#pragma omp parallel // expected-note {{implicitly determined as shared}}
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
#pragma omp parallel
#pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
foo();
#pragma omp parallel private(i)
{
#pragma omp single copyprivate(i)
foo();
}
#pragma omp parallel shared(i) // expected-note {{defined as shared}}
{
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
foo();
}
#pragma omp parallel private(i)
#pragma omp parallel default(shared) // expected-note {{implicitly determined as shared}}
{
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
foo();
}
#pragma omp parallel private(i)
#pragma omp parallel // expected-note {{implicitly determined as shared}}
{
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
foo();
}
#pragma omp parallel
#pragma omp single private(i) copyprivate(i) // expected-error {{private variable cannot be copyprivate}} expected-note {{defined as private}}
foo();
#pragma omp parallel
#pragma omp single firstprivate(i) copyprivate(i) // expected-error {{firstprivate variable cannot be copyprivate}} expected-note {{defined as firstprivate}}
foo();
return tmain(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain<int, char>' requested here}}
}

View File

@ -1989,6 +1989,10 @@ void OMPClauseEnqueue::VisitOMPAlignedClause(const OMPAlignedClause *C) {
void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}
void
OMPClauseEnqueue::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
}
}
void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {