return Res;
}
-static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *RefExpr) {
+static std::pair<ValueDecl *, bool>
+getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
+ SourceRange &ERange, bool AllowArraySection = false) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
- SourceLocation ELoc = RefExpr->getExprLoc();
- SourceRange SR = RefExpr->getSourceRange();
// OpenMP [3.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
RefExpr = RefExpr->IgnoreParens();
+ enum {
+ NoArrayExpr = -1,
+ ArraySubscript = 0,
+ OMPArraySection = 1
+ } IsArrayExpr = NoArrayExpr;
+ if (AllowArraySection) {
+ if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) {
+ auto *Base = ASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ RefExpr = Base;
+ IsArrayExpr = ArraySubscript;
+ } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) {
+ auto *Base = OASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ RefExpr = Base;
+ IsArrayExpr = OMPArraySection;
+ }
+ }
+ ELoc = RefExpr->getExprLoc();
+ ERange = RefExpr->getSourceRange();
+ RefExpr = RefExpr->IgnoreParenImpCasts();
auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr);
if ((!DE || !isa<VarDecl>(DE->getDecl())) &&
(S.getCurrentThisType().isNull() || !ME ||
!isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) ||
!isa<FieldDecl>(ME->getMemberDecl()))) {
- S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr)
- << (S.getCurrentThisType().isNull() ? 0 : 1) << SR;
+ if (IsArrayExpr != NoArrayExpr)
+ S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr
+ << ERange;
+ else {
+ S.Diag(ELoc,
+ AllowArraySection
+ ? diag::err_omp_expected_var_name_member_expr_or_array_item
+ : diag::err_omp_expected_var_name_member_expr)
+ << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange;
+ }
return std::make_pair(nullptr, false);
}
return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false);
SmallVector<Expr *, 8> PrivateCopies;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP private clause.");
- auto Res = getPrivateItem(*this, RefExpr);
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
if (!D)
continue;
- SourceLocation ELoc = RefExpr->getExprLoc();
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
DeclRefExpr *Ref = nullptr;
if (!VD)
- Ref = buildCapture(*this, D, RefExpr);
+ Ref = buildCapture(*this, D, SimpleRefExpr);
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref);
Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref);
PrivateCopies.push_back(VDPrivateRefExpr);
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP firstprivate clause.");
- auto Res = getPrivateItem(*this, RefExpr);
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
if (!D)
continue;
- SourceLocation ELoc =
- IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc();
+ ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc;
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
if (TopDVar.CKind == OMPC_lastprivate)
Ref = TopDVar.PrivateCopy;
else {
- Ref = buildCapture(*this, D, RefExpr);
+ Ref = buildCapture(*this, D, SimpleRefExpr);
if (!IsOpenMPCapturedDecl(D))
ExprCaptures.push_back(Ref->getDecl());
}
SmallVector<Expr *, 4> ExprPostUpdates;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
- auto Res = getPrivateItem(*this, RefExpr);
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
if (!D)
continue;
- SourceLocation ELoc = RefExpr->getExprLoc();
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// lastprivate clause requires an accessible, unambiguous copy assignment
// operator for the class type.
Type = Context.getBaseElementType(Type).getNonReferenceType();
- auto *SrcVD = buildVarDecl(*this, RefExpr->getLocStart(),
+ auto *SrcVD = buildVarDecl(*this, ERange.getBegin(),
Type.getUnqualifiedType(), ".lastprivate.src",
D->hasAttrs() ? &D->getAttrs() : nullptr);
auto *PseudoSrcExpr =
buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc);
auto *DstVD =
- buildVarDecl(*this, RefExpr->getLocStart(), Type, ".lastprivate.dst",
+ buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst",
D->hasAttrs() ? &D->getAttrs() : nullptr);
auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc);
// For arrays generate assignment operation for single element and replace
if (TopDVar.CKind == OMPC_firstprivate)
Ref = TopDVar.PrivateCopy;
else {
- Ref = buildCapture(*this, D, RefExpr);
+ Ref = buildCapture(*this, D, SimpleRefExpr);
if (!IsOpenMPCapturedDecl(D))
ExprCaptures.push_back(Ref->getDecl());
}
if (!RefRes.isUsable())
continue;
ExprResult PostUpdateRes =
- BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
- RefExpr->IgnoreParenLValueCasts(), RefRes.get());
+ BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr,
+ RefRes.get());
if (!PostUpdateRes.isUsable())
continue;
ExprPostUpdates.push_back(PostUpdateRes.get());
SmallVector<Expr *, 8> Vars;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
- auto Res = getPrivateItem(*this, RefExpr);
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
if (!D)
continue;
- SourceLocation ELoc = RefExpr->getExprLoc();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
DeclRefExpr *Ref = nullptr;
if (!VD)
- Ref = buildCapture(*this, D, RefExpr);
+ Ref = buildCapture(*this, D, SimpleRefExpr);
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref);
Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref);
}
};
} // namespace
+namespace {
+// Transform MemberExpression for specified FieldDecl of current class to
+// DeclRefExpr to specified OMPCapturedExprDecl.
+class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> {
+ typedef TreeTransform<TransformExprToCaptures> BaseTransform;
+ ValueDecl *Field;
+ DeclRefExpr *CapturedExpr;
+
+public:
+ TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl)
+ : BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {}
+
+ ExprResult TransformMemberExpr(MemberExpr *E) {
+ if (isa<CXXThisExpr>(E->getBase()->IgnoreParenImpCasts()) &&
+ E->getMemberDecl() == Field) {
+ CapturedExpr = buildCapture(SemaRef, Field, E);
+ return CapturedExpr;
+ }
+ return BaseTransform::TransformMemberExpr(E);
+ }
+ DeclRefExpr *getCapturedExpr() { return CapturedExpr; }
+};
+} // namespace
+
OMPClause *Sema::ActOnOpenMPReductionClause(
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
SmallVector<Expr *, 8> ReductionOps;
for (auto RefExpr : VarList) {
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable or array section, subject to the restrictions
+ // specified in Section 2.4 on page 42 and in each of the sections
+ // describing clauses and directives for which a list appears.
+ // OpenMP [2.14.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
Privates.push_back(nullptr);
LHSs.push_back(nullptr);
RHSs.push_back(nullptr);
ReductionOps.push_back(nullptr);
- continue;
}
-
- if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
- RefExpr->isInstantiationDependent() ||
- RefExpr->containsUnexpandedParameterPack()) {
- // It will be analyzed later.
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
- ReductionOps.push_back(nullptr);
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- auto ELoc = RefExpr->getExprLoc();
- auto ERange = RefExpr->getSourceRange();
- // OpenMP [2.1, C/C++]
- // A list item is a variable or array section, subject to the restrictions
- // specified in Section 2.4 on page 42 and in each of the sections
- // describing clauses and directives for which a list appears.
- // OpenMP [2.14.3.3, Restrictions, p.1]
- // A variable that is part of another variable (as an array or
- // structure element) cannot appear in a private clause.
- auto *DE = dyn_cast<DeclRefExpr>(RefExpr);
- auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr);
- auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr);
- if (!ASE && !OASE && (!DE || !isa<VarDecl>(DE->getDecl()))) {
- Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item)
- << 0 << ERange;
- continue;
- }
QualType Type;
- VarDecl *VD = nullptr;
- if (DE) {
- auto D = DE->getDecl();
- VD = cast<VarDecl>(D);
- Type = Context.getBaseElementType(VD->getType().getNonReferenceType());
- } else if (ASE) {
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens());
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens());
+ if (ASE)
Type = ASE->getType().getNonReferenceType();
- auto *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- DE = dyn_cast<DeclRefExpr>(Base);
- if (DE)
- VD = dyn_cast<VarDecl>(DE->getDecl());
- if (!VD) {
- Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name)
- << 0 << Base->getSourceRange();
- continue;
- }
- } else if (OASE) {
+ else if (OASE) {
auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
if (auto *ATy = BaseType->getAsArrayTypeUnsafe())
Type = ATy->getElementType();
else
Type = BaseType->getPointeeType();
Type = Type.getNonReferenceType();
- auto *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- DE = dyn_cast<DeclRefExpr>(Base);
- if (DE)
- VD = dyn_cast<VarDecl>(DE->getDecl());
- if (!VD) {
- Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name)
- << 1 << Base->getSourceRange();
- continue;
- }
- }
+ } else
+ Type = Context.getBaseElementType(D->getType().getNonReferenceType());
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
Diag(ELoc, diag::err_omp_const_reduction_list_item)
<< getOpenMPClauseName(OMPC_reduction) << Type << ERange;
if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
}
continue;
}
// OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
// If a list-item is a reference type then it must bind to the same object
// for all threads of the team.
- if (!ASE && !OASE) {
+ if (!ASE && !OASE && VD) {
VarDecl *VDDef = VD->getDefinition();
if (VD->getType()->isReferenceType() && VDDef) {
DSARefChecker Check(DSAStack);
Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
<< getLangOpts().CPlusPlus;
if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
}
continue;
}
!getLangOpts().CPlusPlus && Type->isFloatingType()) {
Diag(ELoc, diag::err_omp_clause_floating_type_arg);
if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
}
continue;
}
// but a list item can appear only once in the reduction clauses for that
// directive.
DSAStackTy::DSAVarData DVar;
- DVar = DSAStack->getTopDSA(VD, false);
+ DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind == OMPC_reduction) {
Diag(ELoc, diag::err_omp_once_referenced)
<< getOpenMPClauseName(OMPC_reduction);
- if (DVar.RefExpr) {
+ if (DVar.RefExpr)
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
- }
} else if (DVar.CKind != OMPC_unknown) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_reduction);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir)) {
- DVar = DSAStack->getImplicitDSA(VD, true);
+ DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_reduction)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
}
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
- auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
auto PrivateTy = Type;
if (OASE ||
- (DE && VD->getType().getNonReferenceType()->isVariablyModifiedType())) {
+ (!ASE &&
+ D->getType().getNonReferenceType()->isVariablyModifiedType())) {
// For arays/array sections only:
// Create pseudo array type for private copy. The size for this array will
// be generated during codegen.
Type, new (Context) OpaqueValueExpr(SourceLocation(),
Context.getSizeType(), VK_RValue),
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
- } else if (DE &&
- Context.getAsArrayType(VD->getType().getNonReferenceType()))
- PrivateTy = VD->getType().getNonReferenceType();
+ } else if (!ASE && !OASE &&
+ Context.getAsArrayType(D->getType().getNonReferenceType()))
+ PrivateTy = D->getType().getNonReferenceType();
// Private copy.
- auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
// Add initializer for private variable.
Expr *Init = nullptr;
switch (BOK) {
case BO_Or:
case BO_LOr:
// '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
- if (Type->isScalarType() || Type->isAnyComplexType()) {
+ if (Type->isScalarType() || Type->isAnyComplexType())
Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
- }
break;
case BO_Mul:
case BO_LAnd:
case BO_And: {
// '&' reduction op - initializer is '~0'.
QualType OrigType = Type;
- if (auto *ComplexTy = OrigType->getAs<ComplexType>()) {
+ if (auto *ComplexTy = OrigType->getAs<ComplexType>())
Type = ComplexTy->getElementType();
- }
if (Type->isRealFloatingType()) {
llvm::APFloat InitValue =
llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
if (!RHSVD->hasInit()) {
Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
<< ReductionIdRange;
- if (VD) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- }
+ bool IsDecl =
+ !VD ||
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
continue;
}
// Store initializer for single element in private copy. Will be used during
if (ReductionOp.isInvalid())
continue;
- DSAStack->addDSA(VD, DE, OMPC_reduction);
- Vars.push_back(RefExpr);
+ DeclRefExpr *Ref = nullptr;
+ Expr *VarsExpr = RefExpr->IgnoreParens();
+ if (!VD) {
+ if (ASE || OASE) {
+ TransformExprToCaptures RebuildToCapture(*this, D);
+ VarsExpr =
+ RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get();
+ Ref = RebuildToCapture.getCapturedExpr();
+ } else
+ VarsExpr = Ref = buildCapture(*this, D, SimpleRefExpr);
+ }
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
+ Vars.push_back(VarsExpr);
Privates.push_back(PrivateDRE);
LHSs.push_back(LHSDRE);
RHSs.push_back(RHSDRE);