diff options
Diffstat (limited to 'lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | lib/Sema/SemaOpenMP.cpp | 2385 |
1 files changed, 1867 insertions, 518 deletions
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 36048a38b999..bd68011c18b2 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1,9 +1,8 @@ //===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file @@ -135,7 +134,7 @@ private: /// get the data (loop counters etc.) about enclosing loop-based construct. /// This data is required during codegen. DoacrossDependMapTy DoacrossDepends; - /// first argument (Expr *) contains optional argument of the + /// First argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion; @@ -144,10 +143,14 @@ private: bool NowaitRegion = false; bool CancelRegion = false; bool LoopStart = false; + bool BodyComplete = false; SourceLocation InnerTeamsRegionLoc; /// Reference to the taskgroup task_reduction reference expression. Expr *TaskgroupReductionRef = nullptr; llvm::DenseSet<QualType> MappedClassesQualTypes; + /// List of globals marked as declare target link in this target region + /// (isOpenMPTargetExecutionDirective(Directive) == true). + llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), @@ -170,26 +173,112 @@ private: /// captured by reference. bool ForceCaptureByReferenceInTargetExecutable = false; CriticalsWithHintsTy Criticals; + unsigned IgnoredStackElements = 0; - using iterator = StackTy::const_reverse_iterator; + /// Iterators over the stack iterate in order from innermost to outermost + /// directive. + using const_iterator = StackTy::const_reverse_iterator; + const_iterator begin() const { + return Stack.empty() ? const_iterator() + : Stack.back().first.rbegin() + IgnoredStackElements; + } + const_iterator end() const { + return Stack.empty() ? const_iterator() : Stack.back().first.rend(); + } + using iterator = StackTy::reverse_iterator; + iterator begin() { + return Stack.empty() ? iterator() + : Stack.back().first.rbegin() + IgnoredStackElements; + } + iterator end() { + return Stack.empty() ? iterator() : Stack.back().first.rend(); + } - DSAVarData getDSA(iterator &Iter, ValueDecl *D) const; - - /// Checks if the variable is a local for OpenMP region. - bool isOpenMPLocal(VarDecl *D, iterator Iter) const; + // Convenience operations to get at the elements of the stack. bool isStackEmpty() const { return Stack.empty() || Stack.back().second != CurrentNonCapturingFunctionScope || - Stack.back().first.empty(); + Stack.back().first.size() <= IgnoredStackElements; + } + size_t getStackSize() const { + return isStackEmpty() ? 0 + : Stack.back().first.size() - IgnoredStackElements; + } + + SharingMapTy *getTopOfStackOrNull() { + size_t Size = getStackSize(); + if (Size == 0) + return nullptr; + return &Stack.back().first[Size - 1]; } + const SharingMapTy *getTopOfStackOrNull() const { + return const_cast<DSAStackTy&>(*this).getTopOfStackOrNull(); + } + SharingMapTy &getTopOfStack() { + assert(!isStackEmpty() && "no current directive"); + return *getTopOfStackOrNull(); + } + const SharingMapTy &getTopOfStack() const { + return const_cast<DSAStackTy&>(*this).getTopOfStack(); + } + + SharingMapTy *getSecondOnStackOrNull() { + size_t Size = getStackSize(); + if (Size <= 1) + return nullptr; + return &Stack.back().first[Size - 2]; + } + const SharingMapTy *getSecondOnStackOrNull() const { + return const_cast<DSAStackTy&>(*this).getSecondOnStackOrNull(); + } + + /// Get the stack element at a certain level (previously returned by + /// \c getNestingLevel). + /// + /// Note that nesting levels count from outermost to innermost, and this is + /// the reverse of our iteration order where new inner levels are pushed at + /// the front of the stack. + SharingMapTy &getStackElemAtLevel(unsigned Level) { + assert(Level < getStackSize() && "no such stack element"); + return Stack.back().first[Level]; + } + const SharingMapTy &getStackElemAtLevel(unsigned Level) const { + return const_cast<DSAStackTy&>(*this).getStackElemAtLevel(Level); + } + + DSAVarData getDSA(const_iterator &Iter, ValueDecl *D) const; + + /// Checks if the variable is a local for OpenMP region. + bool isOpenMPLocal(VarDecl *D, const_iterator Iter) const; /// Vector of previously declared requires directives SmallVector<const OMPRequiresDecl *, 2> RequiresDecls; + /// omp_allocator_handle_t type. + QualType OMPAllocatorHandleT; + /// Expression for the predefined allocators. + Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = { + nullptr}; + /// Vector of previously encountered target directives + SmallVector<SourceLocation, 2> TargetLocations; public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} + /// Sets omp_allocator_handle_t type. + void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; } + /// Gets omp_allocator_handle_t type. + QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; } + /// Sets the given default allocator. + void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, + Expr *Allocator) { + OMPPredefinedAllocators[AllocatorKind] = Allocator; + } + /// Returns the specified default allocator. + Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const { + return OMPPredefinedAllocators[AllocatorKind]; + } + bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } OpenMPClauseKind getClauseParsingMode() const { assert(isClauseParsingMode() && "Must be in clause parsing mode."); @@ -197,6 +286,14 @@ public: } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } + bool isBodyComplete() const { + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top && Top->BodyComplete; + } + void setBodyComplete() { + getTopOfStack().BodyComplete = true; + } + bool isForceVarCapturing() const { return ForceCapturing; } void setForceVarCapturing(bool V) { ForceCapturing = V; } @@ -209,6 +306,8 @@ public: void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { + assert(!IgnoredStackElements && + "cannot change stack while ignoring elements"); if (Stack.empty() || Stack.back().second != CurrentNonCapturingFunctionScope) Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope); @@ -217,46 +316,78 @@ public: } void pop() { + assert(!IgnoredStackElements && + "cannot change stack while ignoring elements"); assert(!Stack.back().first.empty() && "Data-sharing attributes stack is empty!"); Stack.back().first.pop_back(); } + /// RAII object to temporarily leave the scope of a directive when we want to + /// logically operate in its parent. + class ParentDirectiveScope { + DSAStackTy &Self; + bool Active; + public: + ParentDirectiveScope(DSAStackTy &Self, bool Activate) + : Self(Self), Active(false) { + if (Activate) + enable(); + } + ~ParentDirectiveScope() { disable(); } + void disable() { + if (Active) { + --Self.IgnoredStackElements; + Active = false; + } + } + void enable() { + if (!Active) { + ++Self.IgnoredStackElements; + Active = true; + } + } + }; + /// Marks that we're started loop parsing. void loopInit() { assert(isOpenMPLoopDirective(getCurrentDirective()) && "Expected loop-based directive."); - Stack.back().first.back().LoopStart = true; + getTopOfStack().LoopStart = true; } /// Start capturing of the variables in the loop context. void loopStart() { assert(isOpenMPLoopDirective(getCurrentDirective()) && "Expected loop-based directive."); - Stack.back().first.back().LoopStart = false; + getTopOfStack().LoopStart = false; } /// true, if variables are captured, false otherwise. bool isLoopStarted() const { assert(isOpenMPLoopDirective(getCurrentDirective()) && "Expected loop-based directive."); - return !Stack.back().first.back().LoopStart; + return !getTopOfStack().LoopStart; } /// Marks (or clears) declaration as possibly loop counter. void resetPossibleLoopCounter(const Decl *D = nullptr) { - Stack.back().first.back().PossiblyLoopCounter = + getTopOfStack().PossiblyLoopCounter = D ? D->getCanonicalDecl() : D; } /// Gets the possible loop counter decl. const Decl *getPossiblyLoopCunter() const { - return Stack.back().first.back().PossiblyLoopCounter; + return getTopOfStack().PossiblyLoopCounter; } /// Start new OpenMP region stack in new non-capturing function. void pushFunction() { + assert(!IgnoredStackElements && + "cannot change stack while ignoring elements"); const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction(); assert(!isa<CapturingScopeInfo>(CurFnScope)); CurrentNonCapturingFunctionScope = CurFnScope; } /// Pop region stack for non-capturing function. void popFunction(const FunctionScopeInfo *OldFSI) { + assert(!IgnoredStackElements && + "cannot change stack while ignoring elements"); if (!Stack.empty() && Stack.back().second == OldFSI) { assert(Stack.back().first.empty()); Stack.pop_back(); @@ -327,16 +458,16 @@ public: Expr *&TaskgroupDescriptor) const; /// Return reduction reference expression for the current taskgroup. Expr *getTaskgroupReductionRef() const { - assert(Stack.back().first.back().Directive == OMPD_taskgroup && + assert(getTopOfStack().Directive == OMPD_taskgroup && "taskgroup reference expression requested for non taskgroup " "directive."); - return Stack.back().first.back().TaskgroupReductionRef; + return getTopOfStack().TaskgroupReductionRef; } /// Checks if the given \p VD declaration is actually a taskgroup reduction /// descriptor variable at the \p Level of OpenMP regions. bool isTaskgroupReductionRef(const ValueDecl *VD, unsigned Level) const { - return Stack.back().first[Level].TaskgroupReductionRef && - cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef) + return getStackElemAtLevel(Level).TaskgroupReductionRef && + cast<DeclRefExpr>(getStackElemAtLevel(Level).TaskgroupReductionRef) ->getDecl() == VD; } @@ -382,18 +513,18 @@ public: /// Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { - return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive; + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->Directive : OMPD_unknown; } /// Returns directive kind at specified level. OpenMPDirectiveKind getDirective(unsigned Level) const { assert(!isStackEmpty() && "No directive at specified level."); - return Stack.back().first[Level].Directive; + return getStackElemAtLevel(Level).Directive; } /// Returns parent directive. OpenMPDirectiveKind getParentDirective() const { - if (isStackEmpty() || Stack.back().first.size() == 1) - return OMPD_unknown; - return std::next(Stack.back().first.rbegin())->Directive; + const SharingMapTy *Parent = getSecondOnStackOrNull(); + return Parent ? Parent->Directive : OMPD_unknown; } /// Add requires decl to internal vector @@ -401,6 +532,16 @@ public: RequiresDecls.push_back(RD); } + /// Checks if the defined 'requires' directive has specified type of clause. + template <typename ClauseType> + bool hasRequiresDeclWithClause() { + return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) { + return llvm::any_of(D->clauselists(), [](const OMPClause *C) { + return isa<ClauseType>(C); + }); + }); + } + /// Checks for a duplicate clause amongst previously declared requires /// directives bool hasDuplicateRequiresClause(ArrayRef<OMPClause *> ClauseList) const { @@ -423,43 +564,50 @@ public: return IsDuplicate; } + /// Add location of previously encountered target to internal vector + void addTargetDirLocation(SourceLocation LocStart) { + TargetLocations.push_back(LocStart); + } + + // Return previously encountered target region locations. + ArrayRef<SourceLocation> getEncounteredTargetLocs() const { + return TargetLocations; + } + /// Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { - assert(!isStackEmpty()); - Stack.back().first.back().DefaultAttr = DSA_none; - Stack.back().first.back().DefaultAttrLoc = Loc; + getTopOfStack().DefaultAttr = DSA_none; + getTopOfStack().DefaultAttrLoc = Loc; } /// Set default data sharing attribute to shared. void setDefaultDSAShared(SourceLocation Loc) { - assert(!isStackEmpty()); - Stack.back().first.back().DefaultAttr = DSA_shared; - Stack.back().first.back().DefaultAttrLoc = Loc; + getTopOfStack().DefaultAttr = DSA_shared; + getTopOfStack().DefaultAttrLoc = Loc; } /// Set default data mapping attribute to 'tofrom:scalar'. void setDefaultDMAToFromScalar(SourceLocation Loc) { - assert(!isStackEmpty()); - Stack.back().first.back().DefaultMapAttr = DMA_tofrom_scalar; - Stack.back().first.back().DefaultMapAttrLoc = Loc; + getTopOfStack().DefaultMapAttr = DMA_tofrom_scalar; + getTopOfStack().DefaultMapAttrLoc = Loc; } DefaultDataSharingAttributes getDefaultDSA() const { return isStackEmpty() ? DSA_unspecified - : Stack.back().first.back().DefaultAttr; + : getTopOfStack().DefaultAttr; } SourceLocation getDefaultDSALocation() const { return isStackEmpty() ? SourceLocation() - : Stack.back().first.back().DefaultAttrLoc; + : getTopOfStack().DefaultAttrLoc; } DefaultMapAttributes getDefaultDMA() const { return isStackEmpty() ? DMA_unspecified - : Stack.back().first.back().DefaultMapAttr; + : getTopOfStack().DefaultMapAttr; } DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const { - return Stack.back().first[Level].DefaultMapAttr; + return getStackElemAtLevel(Level).DefaultMapAttr; } SourceLocation getDefaultDMALocation() const { return isStackEmpty() ? SourceLocation() - : Stack.back().first.back().DefaultMapAttrLoc; + : getTopOfStack().DefaultMapAttrLoc; } /// Checks if the specified variable is a threadprivate. @@ -471,82 +619,77 @@ public: /// Marks current region as ordered (it has an 'ordered' clause). void setOrderedRegion(bool IsOrdered, const Expr *Param, OMPOrderedClause *Clause) { - assert(!isStackEmpty()); if (IsOrdered) - Stack.back().first.back().OrderedRegion.emplace(Param, Clause); + getTopOfStack().OrderedRegion.emplace(Param, Clause); else - Stack.back().first.back().OrderedRegion.reset(); + getTopOfStack().OrderedRegion.reset(); } /// Returns true, if region is ordered (has associated 'ordered' clause), /// false - otherwise. bool isOrderedRegion() const { - if (isStackEmpty()) - return false; - return Stack.back().first.rbegin()->OrderedRegion.hasValue(); + if (const SharingMapTy *Top = getTopOfStackOrNull()) + return Top->OrderedRegion.hasValue(); + return false; } /// Returns optional parameter for the ordered region. std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const { - if (isStackEmpty() || - !Stack.back().first.rbegin()->OrderedRegion.hasValue()) - return std::make_pair(nullptr, nullptr); - return Stack.back().first.rbegin()->OrderedRegion.getValue(); + if (const SharingMapTy *Top = getTopOfStackOrNull()) + if (Top->OrderedRegion.hasValue()) + return Top->OrderedRegion.getValue(); + return std::make_pair(nullptr, nullptr); } /// Returns true, if parent region is ordered (has associated /// 'ordered' clause), false - otherwise. bool isParentOrderedRegion() const { - if (isStackEmpty() || Stack.back().first.size() == 1) - return false; - return std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue(); + if (const SharingMapTy *Parent = getSecondOnStackOrNull()) + return Parent->OrderedRegion.hasValue(); + return false; } /// Returns optional parameter for the ordered region. std::pair<const Expr *, OMPOrderedClause *> getParentOrderedRegionParam() const { - if (isStackEmpty() || Stack.back().first.size() == 1 || - !std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue()) - return std::make_pair(nullptr, nullptr); - return std::next(Stack.back().first.rbegin())->OrderedRegion.getValue(); + if (const SharingMapTy *Parent = getSecondOnStackOrNull()) + if (Parent->OrderedRegion.hasValue()) + return Parent->OrderedRegion.getValue(); + return std::make_pair(nullptr, nullptr); } /// Marks current region as nowait (it has a 'nowait' clause). void setNowaitRegion(bool IsNowait = true) { - assert(!isStackEmpty()); - Stack.back().first.back().NowaitRegion = IsNowait; + getTopOfStack().NowaitRegion = IsNowait; } /// Returns true, if parent region is nowait (has associated /// 'nowait' clause), false - otherwise. bool isParentNowaitRegion() const { - if (isStackEmpty() || Stack.back().first.size() == 1) - return false; - return std::next(Stack.back().first.rbegin())->NowaitRegion; + if (const SharingMapTy *Parent = getSecondOnStackOrNull()) + return Parent->NowaitRegion; + return false; } /// Marks parent region as cancel region. void setParentCancelRegion(bool Cancel = true) { - if (!isStackEmpty() && Stack.back().first.size() > 1) { - auto &StackElemRef = *std::next(Stack.back().first.rbegin()); - StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel; - } + if (SharingMapTy *Parent = getSecondOnStackOrNull()) + Parent->CancelRegion |= Cancel; } /// Return true if current region has inner cancel construct. bool isCancelRegion() const { - return isStackEmpty() ? false : Stack.back().first.back().CancelRegion; + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->CancelRegion : false; } /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { - assert(!isStackEmpty()); - Stack.back().first.back().AssociatedLoops = Val; + getTopOfStack().AssociatedLoops = Val; } /// Return collapse value for region. unsigned getAssociatedLoops() const { - return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops; + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->AssociatedLoops : 0; } /// Marks current target region as one with closely nested teams /// region. void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) { - if (!isStackEmpty() && Stack.back().first.size() > 1) { - std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc = - TeamsRegionLoc; - } + if (SharingMapTy *Parent = getSecondOnStackOrNull()) + Parent->InnerTeamsRegionLoc = TeamsRegionLoc; } /// Returns true, if current region has closely nested teams region. bool hasInnerTeamsRegion() const { @@ -554,16 +697,17 @@ public: } /// Returns location of the nested teams region (if any). SourceLocation getInnerTeamsRegionLoc() const { - return isStackEmpty() ? SourceLocation() - : Stack.back().first.back().InnerTeamsRegionLoc; + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->InnerTeamsRegionLoc : SourceLocation(); } Scope *getCurScope() const { - return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope; + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->CurScope : nullptr; } SourceLocation getConstructLoc() const { - return isStackEmpty() ? SourceLocation() - : Stack.back().first.back().ConstructLoc; + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->ConstructLoc : SourceLocation(); } /// Do the check specified in \a Check to all component lists and return true @@ -576,8 +720,8 @@ public: Check) const { if (isStackEmpty()) return false; - auto SI = Stack.back().first.rbegin(); - auto SE = Stack.back().first.rend(); + auto SI = begin(); + auto SE = end(); if (SI == SE) return false; @@ -606,17 +750,12 @@ public: bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, OpenMPClauseKind)> Check) const { - if (isStackEmpty()) - return false; - - auto StartI = Stack.back().first.begin(); - auto EndI = Stack.back().first.end(); - if (std::distance(StartI, EndI) <= (int)Level) + if (getStackSize() <= Level) return false; - std::advance(StartI, Level); - auto MI = StartI->MappedExprComponents.find(VD); - if (MI != StartI->MappedExprComponents.end()) + const SharingMapTy &StackElem = getStackElemAtLevel(Level); + auto MI = StackElem.MappedExprComponents.find(VD); + if (MI != StackElem.MappedExprComponents.end()) for (OMPClauseMappableExprCommon::MappableExprComponentListRef L : MI->second.Components) if (Check(L, MI->second.Kind)) @@ -630,10 +769,7 @@ public: const ValueDecl *VD, OMPClauseMappableExprCommon::MappableExprComponentListRef Components, OpenMPClauseKind WhereFoundClauseKind) { - assert(!isStackEmpty() && - "Not expecting to retrieve components from a empty stack!"); - MappedExprComponentTy &MEC = - Stack.back().first.back().MappedExprComponents[VD]; + MappedExprComponentTy &MEC = getTopOfStack().MappedExprComponents[VD]; // Create new entry and append the new components there. MEC.Components.resize(MEC.Components.size() + 1); MEC.Components.back().append(Components.begin(), Components.end()); @@ -642,19 +778,17 @@ public: unsigned getNestingLevel() const { assert(!isStackEmpty()); - return Stack.back().first.size() - 1; + return getStackSize() - 1; } void addDoacrossDependClause(OMPDependClause *C, const OperatorOffsetTy &OpsOffs) { - assert(!isStackEmpty() && Stack.back().first.size() > 1); - SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin()); - assert(isOpenMPWorksharingDirective(StackElem.Directive)); - StackElem.DoacrossDepends.try_emplace(C, OpsOffs); + SharingMapTy *Parent = getSecondOnStackOrNull(); + assert(Parent && isOpenMPWorksharingDirective(Parent->Directive)); + Parent->DoacrossDepends.try_emplace(C, OpsOffs); } llvm::iterator_range<DoacrossDependMapTy::const_iterator> getDoacrossDependClauses() const { - assert(!isStackEmpty()); - const SharingMapTy &StackElem = Stack.back().first.back(); + const SharingMapTy &StackElem = getTopOfStack(); if (isOpenMPWorksharingDirective(StackElem.Directive)) { const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends; return llvm::make_range(Ref.begin(), Ref.end()); @@ -665,16 +799,36 @@ public: // Store types of classes which have been explicitly mapped void addMappedClassesQualTypes(QualType QT) { - SharingMapTy &StackElem = Stack.back().first.back(); + SharingMapTy &StackElem = getTopOfStack(); StackElem.MappedClassesQualTypes.insert(QT); } // Return set of mapped classes types bool isClassPreviouslyMapped(QualType QT) const { - const SharingMapTy &StackElem = Stack.back().first.back(); + const SharingMapTy &StackElem = getTopOfStack(); return StackElem.MappedClassesQualTypes.count(QT) != 0; } + /// Adds global declare target to the parent target region. + void addToParentTargetRegionLinkGlobals(DeclRefExpr *E) { + assert(*OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( + E->getDecl()) == OMPDeclareTargetDeclAttr::MT_Link && + "Expected declare target link global."); + for (auto &Elem : *this) { + if (isOpenMPTargetExecutionDirective(Elem.Directive)) { + Elem.DeclareTargetLinkVarDecls.push_back(E); + return; + } + } + } + + /// Returns the list of globals with declare target link if current directive + /// is target. + ArrayRef<DeclRefExpr *> getLinkGlobals() const { + assert(isOpenMPTargetExecutionDirective(getCurrentDirective()) && + "Expected target executable directive."); + return getTopOfStack().DeclareTargetLinkVarDecls; + } }; bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { @@ -682,7 +836,8 @@ bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { } bool isImplicitOrExplicitTaskingRegion(OpenMPDirectiveKind DKind) { - return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || DKind == OMPD_unknown; + return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || + DKind == OMPD_unknown; } } // namespace @@ -728,13 +883,13 @@ static ValueDecl *getCanonicalDecl(ValueDecl *D) { getCanonicalDecl(const_cast<const ValueDecl *>(D))); } -DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter, +DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, ValueDecl *D) const { D = getCanonicalDecl(D); auto *VD = dyn_cast<VarDecl>(D); const auto *FD = dyn_cast<FieldDecl>(D); DSAVarData DVar; - if (isStackEmpty() || Iter == Stack.back().first.rend()) { + if (Iter == end()) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // File-scope or namespace-scope variables referenced in called routines @@ -809,7 +964,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter, // bound to the current team is shared. if (isOpenMPTaskingDirective(DVar.DKind)) { DSAVarData DVarTemp; - iterator I = Iter, E = Stack.back().first.rend(); + const_iterator I = Iter, E = end(); do { ++I; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables @@ -841,7 +996,7 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D, const Expr *NewDE) { assert(!isStackEmpty() && "Data sharing attributes stack is empty"); D = getCanonicalDecl(D); - SharingMapTy &StackElem = Stack.back().first.back(); + SharingMapTy &StackElem = getTopOfStack(); auto It = StackElem.AlignedMap.find(D); if (It == StackElem.AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); @@ -855,7 +1010,7 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D, void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - SharingMapTy &StackElem = Stack.back().first.back(); + SharingMapTy &StackElem = getTopOfStack(); StackElem.LCVMap.try_emplace( D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)); } @@ -864,7 +1019,7 @@ const DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(const ValueDecl *D) const { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - const SharingMapTy &StackElem = Stack.back().first.back(); + const SharingMapTy &StackElem = getTopOfStack(); auto It = StackElem.LCVMap.find(D); if (It != StackElem.LCVMap.end()) return It->second; @@ -873,23 +1028,21 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const { const DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const { - assert(!isStackEmpty() && Stack.back().first.size() > 1 && - "Data-sharing attributes stack is empty"); + const SharingMapTy *Parent = getSecondOnStackOrNull(); + assert(Parent && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin()); - auto It = StackElem.LCVMap.find(D); - if (It != StackElem.LCVMap.end()) + auto It = Parent->LCVMap.find(D); + if (It != Parent->LCVMap.end()) return It->second; return {0, nullptr}; } const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const { - assert(!isStackEmpty() && Stack.back().first.size() > 1 && - "Data-sharing attributes stack is empty"); - const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin()); - if (StackElem.LCVMap.size() < I) + const SharingMapTy *Parent = getSecondOnStackOrNull(); + assert(Parent && "Data-sharing attributes stack is empty"); + if (Parent->LCVMap.size() < I) return nullptr; - for (const auto &Pair : StackElem.LCVMap) + for (const auto &Pair : Parent->LCVMap) if (Pair.second.first == I) return Pair.first; return nullptr; @@ -904,8 +1057,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, Data.RefExpr.setPointer(E); Data.PrivateCopy = nullptr; } else { - assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); - DSAInfo &Data = Stack.back().first.back().SharingMap[D]; + DSAInfo &Data = getTopOfStack().SharingMap[D]; assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) || (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) || (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) || @@ -920,8 +1072,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, Data.RefExpr.setPointerAndInt(E, IsLastprivate); Data.PrivateCopy = PrivateCopy; if (PrivateCopy) { - DSAInfo &Data = - Stack.back().first.back().SharingMap[PrivateCopy->getDecl()]; + DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()]; Data.Attributes = A; Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; @@ -966,16 +1117,16 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); assert( - Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction && + getTopOfStack().SharingMap[D].Attributes == OMPC_reduction && "Additional reduction info may be specified only for reduction items."); - ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D]; + ReductionData &ReductionData = getTopOfStack().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && - Stack.back().first.back().Directive == OMPD_taskgroup && + getTopOfStack().Directive == OMPD_taskgroup && "Additional reduction info may be specified only once for reduction " "items."); ReductionData.set(BOK, SR); Expr *&TaskgroupReductionRef = - Stack.back().first.back().TaskgroupReductionRef; + getTopOfStack().TaskgroupReductionRef; if (!TaskgroupReductionRef) { VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy, ".task_red."); @@ -989,16 +1140,16 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); assert( - Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction && + getTopOfStack().SharingMap[D].Attributes == OMPC_reduction && "Additional reduction info may be specified only for reduction items."); - ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D]; + ReductionData &ReductionData = getTopOfStack().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && - Stack.back().first.back().Directive == OMPD_taskgroup && + getTopOfStack().Directive == OMPD_taskgroup && "Additional reduction info may be specified only once for reduction " "items."); ReductionData.set(ReductionRef, SR); Expr *&TaskgroupReductionRef = - Stack.back().first.back().TaskgroupReductionRef; + getTopOfStack().TaskgroupReductionRef; if (!TaskgroupReductionRef) { VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy, ".task_red."); @@ -1012,11 +1163,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( Expr *&TaskgroupDescriptor) const { D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); - if (Stack.back().first.empty()) - return DSAVarData(); - for (iterator I = std::next(Stack.back().first.rbegin(), 1), - E = Stack.back().first.rend(); - I != E; std::advance(I, 1)) { + for (const_iterator I = begin() + 1, E = end(); I != E; ++I) { const DSAInfo &Data = I->SharingMap.lookup(D); if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) continue; @@ -1041,11 +1188,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( Expr *&TaskgroupDescriptor) const { D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); - if (Stack.back().first.empty()) - return DSAVarData(); - for (iterator I = std::next(Stack.back().first.rbegin(), 1), - E = Stack.back().first.rend(); - I != E; std::advance(I, 1)) { + for (const_iterator I = begin() + 1, E = end(); I != E; ++I) { const DSAInfo &Data = I->SharingMap.lookup(D); if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) continue; @@ -1065,21 +1208,17 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( return DSAVarData(); } -bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const { +bool DSAStackTy::isOpenMPLocal(VarDecl *D, const_iterator I) const { D = D->getCanonicalDecl(); - if (!isStackEmpty()) { - iterator I = Iter, E = Stack.back().first.rend(); - Scope *TopScope = nullptr; - while (I != E && !isImplicitOrExplicitTaskingRegion(I->Directive) && - !isOpenMPTargetExecutionDirective(I->Directive)) - ++I; - if (I == E) - return false; - TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; - Scope *CurScope = getCurScope(); - while (CurScope != TopScope && !CurScope->isDeclScope(D)) - CurScope = CurScope->getParent(); - return CurScope != TopScope; + for (const_iterator E = end(); I != E; ++I) { + if (isImplicitOrExplicitTaskingRegion(I->Directive) || + isOpenMPTargetExecutionDirective(I->Directive)) { + Scope *TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; + Scope *CurScope = getCurScope(); + while (CurScope && CurScope != TopScope && !CurScope->isDeclScope(D)) + CurScope = CurScope->getParent(); + return CurScope != TopScope; + } } return false; } @@ -1167,15 +1306,14 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, if (SemaRef.getLangOpts().OpenMPCUDAMode && VD && VD->isLocalVarDeclOrParm() && !isStackEmpty() && !isLoopControlVariable(D).first) { - iterator IterTarget = - std::find_if(Stack.back().first.rbegin(), Stack.back().first.rend(), - [](const SharingMapTy &Data) { - return isOpenMPTargetExecutionDirective(Data.Directive); - }); - if (IterTarget != Stack.back().first.rend()) { - iterator ParentIterTarget = std::next(IterTarget, 1); - for (iterator Iter = Stack.back().first.rbegin(); - Iter != ParentIterTarget; std::advance(Iter, 1)) { + const_iterator IterTarget = + std::find_if(begin(), end(), [](const SharingMapTy &Data) { + return isOpenMPTargetExecutionDirective(Data.Directive); + }); + if (IterTarget != end()) { + const_iterator ParentIterTarget = IterTarget + 1; + for (const_iterator Iter = begin(); + Iter != ParentIterTarget; ++Iter) { if (isOpenMPLocal(VD, Iter)) { DVar.RefExpr = buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), @@ -1184,7 +1322,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, return DVar; } } - if (!isClauseParsingMode() || IterTarget != Stack.back().first.rbegin()) { + if (!isClauseParsingMode() || IterTarget != begin()) { auto DSAIter = IterTarget->SharingMap.find(D); if (DSAIter != IterTarget->SharingMap.end() && isOpenMPPrivate(DSAIter->getSecond().Attributes)) { @@ -1192,7 +1330,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, DVar.CKind = OMPC_threadprivate; return DVar; } - iterator End = Stack.back().first.rend(); + const_iterator End = end(); if (!SemaRef.isOpenMPCapturedByRef( D, std::distance(ParentIterTarget, End))) { DVar.RefExpr = @@ -1216,16 +1354,28 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, // in a Construct, C/C++, predetermined, p.7] // Variables with static storage duration that are declared in a scope // inside the construct are shared. - auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; }; if (VD && VD->isStaticDataMember()) { - DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent); - if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) + // Check for explicitly specified attributes. + const_iterator I = begin(); + const_iterator EndI = end(); + if (FromParent && I != EndI) + ++I; + auto It = I->SharingMap.find(D); + if (It != I->SharingMap.end()) { + const DSAInfo &Data = It->getSecond(); + DVar.RefExpr = Data.RefExpr.getPointer(); + DVar.PrivateCopy = Data.PrivateCopy; + DVar.CKind = Data.Attributes; + DVar.ImplicitDSALoc = I->DefaultAttrLoc; + DVar.DKind = I->Directive; return DVar; + } DVar.CKind = OMPC_shared; return DVar; } + auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; }; // The predetermined shared attribute for const-qualified types having no // mutable members was removed after OpenMP 3.1. if (SemaRef.LangOpts.OpenMP <= 31) { @@ -1252,10 +1402,10 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, // Explicitly specified attributes and local variables with predetermined // attributes. - iterator I = Stack.back().first.rbegin(); - iterator EndI = Stack.back().first.rend(); + const_iterator I = begin(); + const_iterator EndI = end(); if (FromParent && I != EndI) - std::advance(I, 1); + ++I; auto It = I->SharingMap.find(D); if (It != I->SharingMap.end()) { const DSAInfo &Data = It->getSecond(); @@ -1272,14 +1422,14 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, bool FromParent) const { if (isStackEmpty()) { - iterator I; + const_iterator I; return getDSA(I, D); } D = getCanonicalDecl(D); - iterator StartI = Stack.back().first.rbegin(); - iterator EndI = Stack.back().first.rend(); + const_iterator StartI = begin(); + const_iterator EndI = end(); if (FromParent && StartI != EndI) - std::advance(StartI, 1); + ++StartI; return getDSA(StartI, D); } @@ -1291,14 +1441,15 @@ DSAStackTy::hasDSA(ValueDecl *D, if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - iterator I = Stack.back().first.rbegin(); - iterator EndI = Stack.back().first.rend(); + const_iterator I = begin(); + const_iterator EndI = end(); if (FromParent && I != EndI) - std::advance(I, 1); - for (; I != EndI; std::advance(I, 1)) { - if (!DPred(I->Directive) && !isImplicitOrExplicitTaskingRegion(I->Directive)) + ++I; + for (; I != EndI; ++I) { + if (!DPred(I->Directive) && + !isImplicitOrExplicitTaskingRegion(I->Directive)) continue; - iterator NewI = I; + const_iterator NewI = I; DSAVarData DVar = getDSA(NewI, D); if (I == NewI && CPred(DVar.CKind)) return DVar; @@ -1313,13 +1464,13 @@ const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - iterator StartI = Stack.back().first.rbegin(); - iterator EndI = Stack.back().first.rend(); + const_iterator StartI = begin(); + const_iterator EndI = end(); if (FromParent && StartI != EndI) - std::advance(StartI, 1); + ++StartI; if (StartI == EndI || !DPred(StartI->Directive)) return {}; - iterator NewI = StartI; + const_iterator NewI = StartI; DSAVarData DVar = getDSA(NewI, D); return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData(); } @@ -1327,23 +1478,19 @@ const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( bool DSAStackTy::hasExplicitDSA( const ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred, unsigned Level, bool NotLastprivate) const { - if (isStackEmpty()) + if (getStackSize() <= Level) return false; D = getCanonicalDecl(D); - auto StartI = Stack.back().first.begin(); - auto EndI = Stack.back().first.end(); - if (std::distance(StartI, EndI) <= (int)Level) - return false; - std::advance(StartI, Level); - auto I = StartI->SharingMap.find(D); - if ((I != StartI->SharingMap.end()) && - I->getSecond().RefExpr.getPointer() && - CPred(I->getSecond().Attributes) && - (!NotLastprivate || !I->getSecond().RefExpr.getInt())) + const SharingMapTy &StackElem = getStackElemAtLevel(Level); + auto I = StackElem.SharingMap.find(D); + if (I != StackElem.SharingMap.end() && + I->getSecond().RefExpr.getPointer() && + CPred(I->getSecond().Attributes) && + (!NotLastprivate || !I->getSecond().RefExpr.getInt())) return true; // Check predetermined rules for the loop control variables. - auto LI = StartI->LCVMap.find(D); - if (LI != StartI->LCVMap.end()) + auto LI = StackElem.LCVMap.find(D); + if (LI != StackElem.LCVMap.end()) return CPred(OMPC_private); return false; } @@ -1351,14 +1498,10 @@ bool DSAStackTy::hasExplicitDSA( bool DSAStackTy::hasExplicitDirective( const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, unsigned Level) const { - if (isStackEmpty()) - return false; - auto StartI = Stack.back().first.begin(); - auto EndI = Stack.back().first.end(); - if (std::distance(StartI, EndI) <= (int)Level) + if (getStackSize() <= Level) return false; - std::advance(StartI, Level); - return DPred(StartI->Directive); + const SharingMapTy &StackElem = getStackElemAtLevel(Level); + return DPred(StackElem.Directive); } bool DSAStackTy::hasDirective( @@ -1367,13 +1510,9 @@ bool DSAStackTy::hasDirective( DPred, bool FromParent) const { // We look only in the enclosing region. - if (isStackEmpty()) - return false; - auto StartI = std::next(Stack.back().first.rbegin()); - auto EndI = Stack.back().first.rend(); - if (FromParent && StartI != EndI) - StartI = std::next(StartI); - for (auto I = StartI, EE = EndI; I != EE; ++I) { + size_t Skip = FromParent ? 2 : 1; + for (const_iterator I = begin() + std::min(Skip, getStackSize()), E = end(); + I != E; ++I) { if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc)) return true; } @@ -1394,6 +1533,71 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) { DSAStack->popFunction(OldFSI); } +static bool isOpenMPDeviceDelayedContext(Sema &S) { + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + return !S.isInOpenMPTargetExecutionDirective() && + !S.isInOpenMPDeclareTargetContext(); +} + +/// Do we know that we will eventually codegen the given function? +static bool isKnownEmitted(Sema &S, FunctionDecl *FD) { + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + // Templates are emitted when they're instantiated. + if (FD->isDependentContext()) + return false; + + if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( + FD->getCanonicalDecl())) + return true; + + // Otherwise, the function is known-emitted if it's in our set of + // known-emitted functions. + return S.DeviceKnownEmittedFns.count(FD) > 0; +} + +Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, + unsigned DiagID) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) && + !isKnownEmitted(*this, getCurFunctionDecl())) + ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate, + Loc, DiagID, getCurFunctionDecl(), *this); +} + +void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + assert(Callee && "Callee may not be null."); + FunctionDecl *Caller = getCurFunctionDecl(); + + // If the caller is known-emitted, mark the callee as known-emitted. + // Otherwise, mark the call in our call graph so we can traverse it later. + if (!isOpenMPDeviceDelayedContext(*this) || + (Caller && isKnownEmitted(*this, Caller))) + markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted); + else if (Caller) + DeviceCallGraph[Caller].insert({Callee, Loc}); +} + +void Sema::checkOpenMPDeviceExpr(const Expr *E) { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "OpenMP device compilation mode is expected."); + QualType Ty = E->getType(); + if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || + ((Ty->isFloat128Type() || + (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) && + !Context.getTargetInfo().hasFloat128Type()) || + (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && + !Context.getTargetInfo().hasInt128Type())) + targetDiag(E->getExprLoc(), diag::err_omp_unsupported_type) + << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty + << Context.getTargetInfo().getTriple().str() << E->getSourceRange(); +} + bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); @@ -1523,12 +1727,10 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { if (IsByRef && Ty.getNonReferenceType()->isScalarType()) { IsByRef = - ((DSAStack->isForceCaptureByReferenceInTargetExecutable() && - !Ty->isAnyPointerType()) || - !DSAStack->hasExplicitDSA( - D, - [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, - Level, /*NotLastprivate=*/true)) && + !DSAStack->hasExplicitDSA( + D, + [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true) && // If the variable is artificial and must be captured by value - try to // capture by value. !(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() && @@ -1565,17 +1767,25 @@ bool Sema::isInOpenMPTargetExecutionDirective() const { false); } -VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) { +VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, + unsigned StopAt) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); + // If we want to determine whether the variable should be captured from the + // perspective of the current capturing scope, and we've already left all the + // capturing scopes of the top directive on the stack, check from the + // perspective of its parent directive (if any) instead. + DSAStackTy::ParentDirectiveScope InParentDirectiveRAII( + *DSAStack, CheckScopeInfo && DSAStack->isBodyComplete()); + // If we are attempting to capture a global variable in a directive with // 'target' we return true so that this global is also mapped to the device. // auto *VD = dyn_cast<VarDecl>(D); - if (VD && !VD->hasLocalStorage()) { - if (isInOpenMPDeclareTargetContext() && - (getCurCapturedRegion() || getCurBlock() || getCurLambda())) { + if (VD && !VD->hasLocalStorage() && + (getCurCapturedRegion() || getCurBlock() || getCurLambda())) { + if (isInOpenMPDeclareTargetContext()) { // Try to mark variable as declare target if it is used in capturing // regions. if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) @@ -1590,48 +1800,21 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) { return VD; } } - // Capture variables captured by reference in lambdas for target-based - // directives. - if (VD && !DSAStack->isClauseParsingMode()) { - if (const auto *RD = VD->getType() - .getCanonicalType() - .getNonReferenceType() - ->getAsCXXRecordDecl()) { - bool SavedForceCaptureByReferenceInTargetExecutable = - DSAStack->isForceCaptureByReferenceInTargetExecutable(); - DSAStack->setForceCaptureByReferenceInTargetExecutable(/*V=*/true); - if (RD->isLambda()) { - llvm::DenseMap<const VarDecl *, FieldDecl *> Captures; - FieldDecl *ThisCapture; - RD->getCaptureFields(Captures, ThisCapture); - for (const LambdaCapture &LC : RD->captures()) { - if (LC.getCaptureKind() == LCK_ByRef) { - VarDecl *VD = LC.getCapturedVar(); - DeclContext *VDC = VD->getDeclContext(); - if (!VDC->Encloses(CurContext)) - continue; - DSAStackTy::DSAVarData DVarPrivate = - DSAStack->getTopDSA(VD, /*FromParent=*/false); - // Do not capture already captured variables. - if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) && - DVarPrivate.CKind == OMPC_unknown && - !DSAStack->checkMappableExprComponentListsForDecl( - D, /*CurrentRegionOnly=*/true, - [](OMPClauseMappableExprCommon:: - MappableExprComponentListRef, - OpenMPClauseKind) { return true; })) - MarkVariableReferenced(LC.getLocation(), LC.getCapturedVar()); - } else if (LC.getCaptureKind() == LCK_This) { - QualType ThisTy = getCurrentThisType(); - if (!ThisTy.isNull() && - Context.typesAreCompatible(ThisTy, ThisCapture->getType())) - CheckCXXThisCapture(LC.getLocation()); - } + + if (CheckScopeInfo) { + bool OpenMPFound = false; + for (unsigned I = StopAt + 1; I > 0; --I) { + FunctionScopeInfo *FSI = FunctionScopes[I - 1]; + if(!isa<CapturingScopeInfo>(FSI)) + return nullptr; + if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI)) + if (RSI->CapRegionKind == CR_OpenMP) { + OpenMPFound = true; + break; } - } - DSAStack->setForceCaptureByReferenceInTargetExecutable( - SavedForceCaptureByReferenceInTargetExecutable); } + if (!OpenMPFound) + return nullptr; } if (DSAStack->getCurrentDirective() != OMPD_unknown && @@ -1647,10 +1830,16 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) { DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); + // Threadprivate variables must not be captured. + if (isOpenMPThreadPrivate(DVarPrivate.CKind)) + return nullptr; + // The variable is not private or it is the variable in the directive with + // default(none) clause and not used in any clause. DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; }, DSAStack->isClauseParsingMode()); - if (DVarPrivate.CKind != OMPC_unknown) + if (DVarPrivate.CKind != OMPC_unknown || + (VD && DSAStack->getDefaultDSA() == DSA_none)) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } return nullptr; @@ -1764,6 +1953,9 @@ void Sema::EndOpenMPClause() { DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses); + void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a lastprivate @@ -1794,8 +1986,10 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { *this, DE->getExprLoc(), Type.getUnqualifiedType(), VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE); ActOnUninitializedDecl(VDPrivate); - if (VDPrivate->isInvalidDecl()) + if (VDPrivate->isInvalidDecl()) { + PrivateCopies.push_back(nullptr); continue; + } PrivateCopies.push_back(buildDeclRefExpr( *this, VDPrivate, DE->getType(), DE->getExprLoc())); } else { @@ -1804,11 +1998,12 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PrivateCopies.push_back(nullptr); } } - // Set initializers to private copies if no errors were found. - if (PrivateCopies.size() == Clause->varlist_size()) - Clause->setPrivateCopies(PrivateCopies); + Clause->setPrivateCopies(PrivateCopies); } } + // Check allocate clauses. + if (!CurContext->isDependentContext()) + checkAllocateClauses(*this, DSAStack, D->clauses()); } DSAStack->pop(); @@ -1837,6 +2032,11 @@ public: } return false; } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<VarDeclFilterCCC>(*this); + } + }; class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback { @@ -1847,19 +2047,25 @@ public: explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); - if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) { + if (ND && ((isa<VarDecl>(ND) && ND->getKind() == Decl::Var) || + isa<FunctionDecl>(ND))) { return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), SemaRef.getCurScope()); } return false; } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this); + } }; } // namespace ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, - const DeclarationNameInfo &Id) { + const DeclarationNameInfo &Id, + OpenMPDirectiveKind Kind) { LookupResult Lookup(*this, Id, LookupOrdinaryName); LookupParsedName(Lookup, CurScope, &ScopeSpec, true); @@ -1868,9 +2074,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, VarDecl *VD; if (!Lookup.isSingleResult()) { - if (TypoCorrection Corrected = CorrectTypo( - Id, LookupOrdinaryName, CurScope, nullptr, - llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) { + VarDeclFilterCCC CCC(*this); + if (TypoCorrection Corrected = + CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC, + CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(Lookup.empty() ? diag::err_undeclared_var_use_suggest @@ -1892,9 +2099,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Syntax, C/C++] // Variables must be file-scope, namespace-scope, or static block-scope. - if (!VD->hasGlobalStorage()) { + if (Kind == OMPD_threadprivate && !VD->hasGlobalStorage()) { Diag(Id.getLoc(), diag::err_omp_global_var_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal(); + << getOpenMPDirectiveName(Kind) << !VD->isStaticLocal(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1911,7 +2118,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, if (CanonicalVD->getDeclContext()->isTranslationUnit() && !getCurLexicalContext()->isTranslationUnit()) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1926,7 +2133,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, if (CanonicalVD->isStaticDataMember() && !CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1942,7 +2149,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, (!getCurLexicalContext()->isFileContext() || !getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1953,10 +2160,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Restrictions, C/C++, p.6] // A threadprivate directive for static block-scope variables must appear // in the scope of the variable and not in a nested scope. - if (CanonicalVD->isStaticLocal() && CurScope && + if (CanonicalVD->isLocalVarDecl() && CurScope && !isDeclInScope(ND, getCurLexicalContext(), CurScope)) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1968,9 +2175,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] // A threadprivate directive must lexically precede all references to any // of the variables in its list. - if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) { + if (Kind == OMPD_threadprivate && VD->isUsed() && + !DSAStack->isThreadPrivate(VD)) { Diag(Id.getLoc(), diag::err_omp_var_used) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; return ExprError(); } @@ -2102,6 +2310,167 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { return D; } +static OMPAllocateDeclAttr::AllocatorTypeTy +getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) { + if (!Allocator) + return OMPAllocateDeclAttr::OMPDefaultMemAlloc; + if (Allocator->isTypeDependent() || Allocator->isValueDependent() || + Allocator->isInstantiationDependent() || + Allocator->containsUnexpandedParameterPack()) + return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; + auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; + const Expr *AE = Allocator->IgnoreParenImpCasts(); + for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; + I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); + const Expr *DefAllocator = Stack->getAllocator(AllocatorKind); + llvm::FoldingSetNodeID AEId, DAEId; + AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true); + DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true); + if (AEId == DAEId) { + AllocatorKindRes = AllocatorKind; + break; + } + } + return AllocatorKindRes; +} + +static bool checkPreviousOMPAllocateAttribute( + Sema &S, DSAStackTy *Stack, Expr *RefExpr, VarDecl *VD, + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) { + if (!VD->hasAttr<OMPAllocateDeclAttr>()) + return false; + const auto *A = VD->getAttr<OMPAllocateDeclAttr>(); + Expr *PrevAllocator = A->getAllocator(); + OMPAllocateDeclAttr::AllocatorTypeTy PrevAllocatorKind = + getAllocatorKind(S, Stack, PrevAllocator); + bool AllocatorsMatch = AllocatorKind == PrevAllocatorKind; + if (AllocatorsMatch && + AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc && + Allocator && PrevAllocator) { + const Expr *AE = Allocator->IgnoreParenImpCasts(); + const Expr *PAE = PrevAllocator->IgnoreParenImpCasts(); + llvm::FoldingSetNodeID AEId, PAEId; + AE->Profile(AEId, S.Context, /*Canonical=*/true); + PAE->Profile(PAEId, S.Context, /*Canonical=*/true); + AllocatorsMatch = AEId == PAEId; + } + if (!AllocatorsMatch) { + SmallString<256> AllocatorBuffer; + llvm::raw_svector_ostream AllocatorStream(AllocatorBuffer); + if (Allocator) + Allocator->printPretty(AllocatorStream, nullptr, S.getPrintingPolicy()); + SmallString<256> PrevAllocatorBuffer; + llvm::raw_svector_ostream PrevAllocatorStream(PrevAllocatorBuffer); + if (PrevAllocator) + PrevAllocator->printPretty(PrevAllocatorStream, nullptr, + S.getPrintingPolicy()); + + SourceLocation AllocatorLoc = + Allocator ? Allocator->getExprLoc() : RefExpr->getExprLoc(); + SourceRange AllocatorRange = + Allocator ? Allocator->getSourceRange() : RefExpr->getSourceRange(); + SourceLocation PrevAllocatorLoc = + PrevAllocator ? PrevAllocator->getExprLoc() : A->getLocation(); + SourceRange PrevAllocatorRange = + PrevAllocator ? PrevAllocator->getSourceRange() : A->getRange(); + S.Diag(AllocatorLoc, diag::warn_omp_used_different_allocator) + << (Allocator ? 1 : 0) << AllocatorStream.str() + << (PrevAllocator ? 1 : 0) << PrevAllocatorStream.str() + << AllocatorRange; + S.Diag(PrevAllocatorLoc, diag::note_omp_previous_allocator) + << PrevAllocatorRange; + return true; + } + return false; +} + +static void +applyOMPAllocateAttribute(Sema &S, VarDecl *VD, + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, + Expr *Allocator, SourceRange SR) { + if (VD->hasAttr<OMPAllocateDeclAttr>()) + return; + if (Allocator && + (Allocator->isTypeDependent() || Allocator->isValueDependent() || + Allocator->isInstantiationDependent() || + Allocator->containsUnexpandedParameterPack())) + return; + auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind, + Allocator, SR); + VD->addAttr(A); + if (ASTMutationListener *ML = S.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPAllocate(VD, A); +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective( + SourceLocation Loc, ArrayRef<Expr *> VarList, + ArrayRef<OMPClause *> Clauses, DeclContext *Owner) { + assert(Clauses.size() <= 1 && "Expected at most one clause."); + Expr *Allocator = nullptr; + if (Clauses.empty()) { + // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions. + // allocate directives that appear in a target region must specify an + // allocator clause unless a requires directive with the dynamic_allocators + // clause is present in the same compilation unit. + if (LangOpts.OpenMPIsDevice && + !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>()) + targetDiag(Loc, diag::err_expected_allocator_clause); + } else { + Allocator = cast<OMPAllocatorClause>(Clauses.back())->getAllocator(); + } + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = + getAllocatorKind(*this, DSAStack, Allocator); + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + auto *DE = cast<DeclRefExpr>(RefExpr); + auto *VD = cast<VarDecl>(DE->getDecl()); + + // Check if this is a TLS variable or global register. + if (VD->getTLSKind() != VarDecl::TLS_None || + VD->hasAttr<OMPThreadPrivateDeclAttr>() || + (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && + !VD->isLocalVarDecl())) + continue; + + // If the used several times in the allocate directive, the same allocator + // must be used. + if (checkPreviousOMPAllocateAttribute(*this, DSAStack, RefExpr, VD, + AllocatorKind, Allocator)) + continue; + + // OpenMP, 2.11.3 allocate Directive, Restrictions, C / C++ + // If a list item has a static storage type, the allocator expression in the + // allocator clause must be a constant expression that evaluates to one of + // the predefined memory allocator values. + if (Allocator && VD->hasGlobalStorage()) { + if (AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc) { + Diag(Allocator->getExprLoc(), + diag::err_omp_expected_predefined_allocator) + << Allocator->getSourceRange(); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + } + + Vars.push_back(RefExpr); + applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, + DE->getSourceRange()); + } + if (Vars.empty()) + return nullptr; + if (!Owner) + Owner = getCurLexicalContext(); + auto *D = OMPAllocateDecl::Create(Context, Owner, Loc, Vars, Clauses); + D->setAccess(AS_public); + Owner->addDecl(D); + return DeclGroupPtrTy::make(DeclGroupRef(D)); +} + Sema::DeclGroupPtrTy Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc, ArrayRef<OMPClause *> ClauseList) { @@ -2120,6 +2489,27 @@ Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc, OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc, ArrayRef<OMPClause *> ClauseList) { + /// For target specific clauses, the requires directive cannot be + /// specified after the handling of any of the target regions in the + /// current compilation unit. + ArrayRef<SourceLocation> TargetLocations = + DSAStack->getEncounteredTargetLocs(); + if (!TargetLocations.empty()) { + for (const OMPClause *CNew : ClauseList) { + // Check if any of the requires clauses affect target regions. + if (isa<OMPUnifiedSharedMemoryClause>(CNew) || + isa<OMPUnifiedAddressClause>(CNew) || + isa<OMPReverseOffloadClause>(CNew) || + isa<OMPDynamicAllocatorsClause>(CNew)) { + Diag(Loc, diag::err_omp_target_before_requires) + << getOpenMPClauseName(CNew->getClauseKind()); + for (SourceLocation TargetLoc : TargetLocations) { + Diag(TargetLoc, diag::note_omp_requires_encountered_target); + } + } + } + } + if (!DSAStack->hasDuplicateRequiresClause(ClauseList)) return OMPRequiresDecl::Create(Context, getCurLexicalContext(), Loc, ClauseList); @@ -2198,24 +2588,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { // Check implicitly captured variables. if (!S->hasAssociatedStmt() || !S->getAssociatedStmt()) return; - for (const CapturedStmt::Capture &Cap : - S->getInnermostCapturedStmt()->captures()) { - if (!Cap.capturesVariable()) - continue; - VarDecl *VD = Cap.getCapturedVar(); - // Do not try to map the variable if it or its sub-component was mapped - // already. - if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && - Stack->checkMappableExprComponentListsForDecl( - VD, /*CurrentRegionOnly=*/true, - [](OMPClauseMappableExprCommon::MappableExprComponentListRef, - OpenMPClauseKind) { return true; })) - continue; - DeclRefExpr *DRE = buildDeclRefExpr( - SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context), - Cap.getLocation(), /*RefersToCapture=*/true); - Visit(DRE); - } + visitSubCaptures(S->getInnermostCapturedStmt()); } public: @@ -2224,9 +2597,20 @@ public: E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) return; if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { + // Check the datasharing rules for the expressions in the clauses. + if (!CS) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD)) + if (!CED->hasAttr<OMPCaptureNoInitAttr>()) { + Visit(CED->getInit()); + return; + } + } else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(VD)) + // Do not analyze internal variables and do not enclose them into + // implicit clauses. + return; VD = VD->getCanonicalDecl(); // Skip internally declared variables. - if (VD->hasLocalStorage() && !CS->capturesVariable(VD)) + if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD)) return; DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false); @@ -2237,8 +2621,9 @@ public: // Skip internally declared static variables. llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); - if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) && - (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)) + if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) && + (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || + !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)) return; SourceLocation ELoc = E->getExprLoc(); @@ -2315,8 +2700,18 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false); if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && - !Stack->isLoopControlVariable(VD).first) + !Stack->isLoopControlVariable(VD).first) { ImplicitFirstprivate.push_back(E); + return; + } + + // Store implicitly used globals with declare target link for parent + // target. + if (!isOpenMPTargetExecutionDirective(DKind) && Res && + *Res == OMPDeclareTargetDeclAttr::MT_Link) { + Stack->addToParentTargetRegionLinkGlobals(E); + return; + } } } void VisitMemberExpr(MemberExpr *E) { @@ -2464,6 +2859,25 @@ public: } } + void visitSubCaptures(CapturedStmt *S) { + for (const CapturedStmt::Capture &Cap : S->captures()) { + if (!Cap.capturesVariable() && !Cap.capturesVariableByCopy()) + continue; + VarDecl *VD = Cap.getCapturedVar(); + // Do not try to map the variable if it or its sub-component was mapped + // already. + if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && + Stack->checkMappableExprComponentListsForDecl( + VD, /*CurrentRegionOnly=*/true, + [](OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind) { return true; })) + continue; + DeclRefExpr *DRE = buildDeclRefExpr( + SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context), + Cap.getLocation(), /*RefersToCapture=*/true); + Visit(DRE); + } + } bool isErrorFound() const { return ErrorFound; } ArrayRef<Expr *> getImplicitFirstprivate() const { return ImplicitFirstprivate; @@ -2474,7 +2888,13 @@ public: } DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS) - : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {} + : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) { + // Process declare target link variables for the target directives. + if (isOpenMPTargetExecutionDirective(S->getCurrentDirective())) { + for (DeclRefExpr *E : Stack->getLinkGlobals()) + Visit(E); + } + } }; } // namespace @@ -2802,6 +3222,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: @@ -2809,6 +3230,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancel: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -2915,6 +3337,46 @@ public: }; } // namespace +void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) { + // Capture variables captured by reference in lambdas for target-based + // directives. + if (!CurContext->isDependentContext() && + (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) || + isOpenMPTargetDataManagementDirective( + DSAStack->getCurrentDirective()))) { + QualType Type = V->getType(); + if (const auto *RD = Type.getCanonicalType() + .getNonReferenceType() + ->getAsCXXRecordDecl()) { + bool SavedForceCaptureByReferenceInTargetExecutable = + DSAStack->isForceCaptureByReferenceInTargetExecutable(); + DSAStack->setForceCaptureByReferenceInTargetExecutable( + /*V=*/true); + if (RD->isLambda()) { + llvm::DenseMap<const VarDecl *, FieldDecl *> Captures; + FieldDecl *ThisCapture; + RD->getCaptureFields(Captures, ThisCapture); + for (const LambdaCapture &LC : RD->captures()) { + if (LC.getCaptureKind() == LCK_ByRef) { + VarDecl *VD = LC.getCapturedVar(); + DeclContext *VDC = VD->getDeclContext(); + if (!VDC->Encloses(CurContext)) + continue; + MarkVariableReferenced(LC.getLocation(), VD); + } else if (LC.getCaptureKind() == LCK_This) { + QualType ThisTy = getCurrentThisType(); + if (!ThisTy.isNull() && + Context.typesAreCompatible(ThisTy, ThisCapture->getType())) + CheckCXXThisCapture(LC.getLocation()); + } + } + } + DSAStack->setForceCaptureByReferenceInTargetExecutable( + SavedForceCaptureByReferenceInTargetExecutable); + } + } +} + StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses) { bool ErrorFound = false; @@ -3004,6 +3466,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, return StmtError(); } StmtResult SR = S; + unsigned CompletedRegions = 0; for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(CaptureRegions)) { // Mark all variables in private list clauses as used in inner region. // Required for proper codegen of combined directives. @@ -3025,6 +3488,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } } } + if (++CompletedRegions == CaptureRegions.size()) + DSAStack->setBodyComplete(); SR = ActOnCapturedRegionEnd(SR.get()); } return SR; @@ -3346,6 +3811,169 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, return ErrorFound; } +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); + + // 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)) { + Expr *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)) { + Expr *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()))) { + 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( + getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); +} + +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses) { + assert(!S.CurContext->isDependentContext() && + "Expected non-dependent context."); + auto AllocateRange = + llvm::make_filter_range(Clauses, OMPAllocateClause::classof); + llvm::DenseMap<CanonicalDeclPtr<Decl>, CanonicalDeclPtr<VarDecl>> + DeclToCopy; + auto PrivateRange = llvm::make_filter_range(Clauses, [](const OMPClause *C) { + return isOpenMPPrivate(C->getClauseKind()); + }); + for (OMPClause *Cl : PrivateRange) { + MutableArrayRef<Expr *>::iterator I, It, Et; + if (Cl->getClauseKind() == OMPC_private) { + auto *PC = cast<OMPPrivateClause>(Cl); + I = PC->private_copies().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_firstprivate) { + auto *PC = cast<OMPFirstprivateClause>(Cl); + I = PC->private_copies().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_lastprivate) { + auto *PC = cast<OMPLastprivateClause>(Cl); + I = PC->private_copies().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_linear) { + auto *PC = cast<OMPLinearClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_reduction) { + auto *PC = cast<OMPReductionClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_task_reduction) { + auto *PC = cast<OMPTaskReductionClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_in_reduction) { + auto *PC = cast<OMPInReductionClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else { + llvm_unreachable("Expected private clause."); + } + for (Expr *E : llvm::make_range(It, Et)) { + if (!*I) { + ++I; + continue; + } + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = E; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + DeclToCopy.try_emplace(Res.first, + cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl())); + ++I; + } + } + for (OMPClause *C : AllocateRange) { + auto *AC = cast<OMPAllocateClause>(C); + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = + getAllocatorKind(S, Stack, AC->getAllocator()); + // OpenMP, 2.11.4 allocate Clause, Restrictions. + // For task, taskloop or target directives, allocation requests to memory + // allocators with the trait access set to thread result in unspecified + // behavior. + if (AllocatorKind == OMPAllocateDeclAttr::OMPThreadMemAlloc && + (isOpenMPTaskingDirective(Stack->getCurrentDirective()) || + isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()))) { + S.Diag(AC->getAllocator()->getExprLoc(), + diag::warn_omp_allocate_thread_on_task_target_directive) + << getOpenMPDirectiveName(Stack->getCurrentDirective()); + } + for (Expr *E : AC->varlists()) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = E; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange); + ValueDecl *VD = Res.first; + DSAStackTy::DSAVarData Data = Stack->getTopDSA(VD, /*FromParent=*/false); + if (!isOpenMPPrivate(Data.CKind)) { + S.Diag(E->getExprLoc(), + diag::err_omp_expected_private_copy_for_allocate); + continue; + } + VarDecl *PrivateVD = DeclToCopy[VD]; + if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD, + AllocatorKind, AC->getAllocator())) + continue; + applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(), + E->getSourceRange()); + } + } +} + StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, @@ -3371,6 +3999,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( while (--ThisCaptureLevel >= 0) S = cast<CapturedStmt>(S)->getCapturedStmt(); DSAChecker.Visit(S); + if (!isOpenMPTargetDataManagementDirective(Kind) && + !isOpenMPTaskingDirective(Kind)) { + // Visit subcaptures to generate implicit clauses for captured vars. + auto *CS = cast<CapturedStmt>(AStmt); + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, Kind); + // Ignore outer tasking regions for target directives. + if (CaptureRegions.size() > 1 && CaptureRegions.front() == OMPD_task) + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + DSAChecker.visitSubCaptures(CS); + } if (DSAChecker.isErrorFound()) return StmtError(); // Generate list of implicitly defined firstprivate variables. @@ -3401,11 +4040,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( } } if (!ImplicitMaps.empty()) { + CXXScopeSpec MapperIdScopeSpec; + DeclarationNameInfo MapperId; if (OMPClause *Implicit = ActOnOpenMPMapClause( - llvm::None, llvm::None, OMPC_MAP_tofrom, - /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), - ImplicitMaps, SourceLocation(), SourceLocation(), - SourceLocation())) { + llvm::None, llvm::None, MapperIdScopeSpec, MapperId, + OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(), + SourceLocation(), ImplicitMaps, OMPVarListLocTy())) { ClausesWithImplicit.emplace_back(Implicit); ErrorFound |= cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size(); @@ -3656,7 +4296,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_requires: llvm_unreachable("OpenMP Directive is not allowed"); @@ -3664,11 +4306,99 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( llvm_unreachable("Unknown OpenMP directive"); } + ErrorFound = Res.isInvalid() || ErrorFound; + + // Check variables in the clauses if default(none) was specified. + if (DSAStack->getDefaultDSA() == DSA_none) { + DSAAttrChecker DSAChecker(DSAStack, *this, nullptr); + for (OMPClause *C : Clauses) { + switch (C->getClauseKind()) { + case OMPC_num_threads: + case OMPC_dist_schedule: + // Do not analyse if no parent teams directive. + if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective())) + break; + continue; + case OMPC_if: + if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) && + cast<OMPIfClause>(C)->getNameModifier() != OMPD_target) + break; + continue; + case OMPC_schedule: + break; + case OMPC_ordered: + case OMPC_device: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_hint: + case OMPC_collapse: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_final: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_shared: + case OMPC_reduction: + case OMPC_task_reduction: + case OMPC_in_reduction: + case OMPC_linear: + case OMPC_aligned: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + case OMPC_allocate: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_threads: + case OMPC_simd: + case OMPC_map: + case OMPC_nogroup: + case OMPC_defaultmap: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: + continue; + case OMPC_allocator: + case OMPC_flush: + case OMPC_threadprivate: + case OMPC_uniform: + case OMPC_unknown: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: + case OMPC_atomic_default_mem_order: + llvm_unreachable("Unexpected clause"); + } + for (Stmt *CC : C->children()) { + if (CC) + DSAChecker.Visit(CC); + } + } + for (auto &P : DSAChecker.getVarsWithInheritedDSA()) + VarsWithInheritedDSA[P.getFirst()] = P.getSecond(); + } for (const auto &P : VarsWithInheritedDSA) { + if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst())) + continue; + ErrorFound = true; Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); + Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none); } - ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound; if (!AllowedNameModifiers.empty()) ErrorFound = checkIfClauses(*this, Kind, Clauses, AllowedNameModifiers) || @@ -3676,6 +4406,23 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (ErrorFound) return StmtError(); + + if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) { + Res.getAs<OMPExecutableDirective>() + ->getStructuredBlock() + ->setIsOMPStructuredBlock(true); + } + + if (!CurContext->isDependentContext() && + isOpenMPTargetExecutionDirective(Kind) && + !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || + DSAStack->hasRequiresDeclWithClause<OMPUnifiedAddressClause>() || + DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>() || + DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())) { + // Register target to DSA Stack. + DSAStack->addTargetDirLocation(StartLoc); + } + return Res; } @@ -3953,6 +4700,8 @@ namespace { class OpenMPIterationSpaceChecker { /// Reference to Sema. Sema &SemaRef; + /// Data-sharing stack. + DSAStackTy &Stack; /// A location for diagnostics (when there is no some better location). SourceLocation DefaultLoc; /// A location for diagnostics (when increment is not compatible). @@ -3984,10 +4733,22 @@ class OpenMPIterationSpaceChecker { bool TestIsStrictOp = false; /// This flag is true when step is subtracted on each iteration. bool SubtractStep = false; + /// The outer loop counter this loop depends on (if any). + const ValueDecl *DepDecl = nullptr; + /// Contains number of loop (starts from 1) on which loop counter init + /// expression of this loop depends on. + Optional<unsigned> InitDependOnLC; + /// Contains number of loop (starts from 1) on which loop counter condition + /// expression of this loop depends on. + Optional<unsigned> CondDependOnLC; + /// Checks if the provide statement depends on the loop counter. + Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); public: - OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) - : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} + OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, + SourceLocation DefaultLoc) + : SemaRef(SemaRef), Stack(Stack), DefaultLoc(DefaultLoc), + ConditionLoc(DefaultLoc) {} /// Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool checkAndSetInit(Stmt *S, bool EmitDiags = true); @@ -4009,6 +4770,8 @@ public: SourceRange getIncrementSrcRange() const { return IncrementSrcRange; } /// True if the step should be subtracted. bool shouldSubtractStep() const { return SubtractStep; } + /// True, if the compare operator is strict (<, > or !=). + bool isStrictTestOp() const { return TestIsStrictOp; } /// Build the expression to calculate the number of iterations. Expr *buildNumIterations( Scope *S, const bool LimitedType, @@ -4043,7 +4806,8 @@ private: /// expression. bool checkAndSetIncRHS(Expr *RHS); /// Helper to set loop counter variable and its initializer. - bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); + bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB, + bool EmitDiags); /// Helper to set upper bound. bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); @@ -4063,7 +4827,7 @@ bool OpenMPIterationSpaceChecker::dependent() const { bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewLCRefExpr, - Expr *NewLB) { + Expr *NewLB, bool EmitDiags) { // State consistency checking to ensure correct usage. assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); @@ -4078,10 +4842,13 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) NewLB = CE->getArg(0)->IgnoreParenImpCasts(); LB = NewLB; + if (EmitDiags) + InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true); return false; } -bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp, +bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, + llvm::Optional<bool> LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. @@ -4095,6 +4862,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp TestIsStrictOp = StrictOp; ConditionSrcRange = SR; ConditionLoc = SL; + CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false); return false; } @@ -4160,6 +4928,110 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { return false; } +namespace { +/// Checker for the non-rectangular loops. Checks if the initializer or +/// condition expression references loop counter variable. +class LoopCounterRefChecker final + : public ConstStmtVisitor<LoopCounterRefChecker, bool> { + Sema &SemaRef; + DSAStackTy &Stack; + const ValueDecl *CurLCDecl = nullptr; + const ValueDecl *DepDecl = nullptr; + const ValueDecl *PrevDepDecl = nullptr; + bool IsInitializer = true; + unsigned BaseLoopId = 0; + bool checkDecl(const Expr *E, const ValueDecl *VD) { + if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) { + SemaRef.Diag(E->getExprLoc(), diag::err_omp_stmt_depends_on_loop_counter) + << (IsInitializer ? 0 : 1); + return false; + } + const auto &&Data = Stack.isLoopControlVariable(VD); + // OpenMP, 2.9.1 Canonical Loop Form, Restrictions. + // The type of the loop iterator on which we depend may not have a random + // access iterator type. + if (Data.first && VD->getType()->isRecordType()) { + SmallString<128> Name; + llvm::raw_svector_ostream OS(Name); + VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), + /*Qualified=*/true); + SemaRef.Diag(E->getExprLoc(), + diag::err_omp_wrong_dependency_iterator_type) + << OS.str(); + SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD; + return false; + } + if (Data.first && + (DepDecl || (PrevDepDecl && + getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) { + if (!DepDecl && PrevDepDecl) + DepDecl = PrevDepDecl; + SmallString<128> Name; + llvm::raw_svector_ostream OS(Name); + DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), + /*Qualified=*/true); + SemaRef.Diag(E->getExprLoc(), + diag::err_omp_invariant_or_linear_dependency) + << OS.str(); + return false; + } + if (Data.first) { + DepDecl = VD; + BaseLoopId = Data.first; + } + return Data.first; + } + +public: + bool VisitDeclRefExpr(const DeclRefExpr *E) { + const ValueDecl *VD = E->getDecl(); + if (isa<VarDecl>(VD)) + return checkDecl(E, VD); + return false; + } + bool VisitMemberExpr(const MemberExpr *E) { + if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) { + const ValueDecl *VD = E->getMemberDecl(); + if (isa<VarDecl>(VD) || isa<FieldDecl>(VD)) + return checkDecl(E, VD); + } + return false; + } + bool VisitStmt(const Stmt *S) { + bool Res = true; + for (const Stmt *Child : S->children()) + Res = Child && Visit(Child) && Res; + return Res; + } + explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, + const ValueDecl *CurLCDecl, bool IsInitializer, + const ValueDecl *PrevDepDecl = nullptr) + : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl), + PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer) {} + unsigned getBaseLoopId() const { + assert(CurLCDecl && "Expected loop dependency."); + return BaseLoopId; + } + const ValueDecl *getDepDecl() const { + assert(CurLCDecl && "Expected loop dependency."); + return DepDecl; + } +}; +} // namespace + +Optional<unsigned> +OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, + bool IsInitializer) { + // Check for the non-rectangular loops. + LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer, + DepDecl); + if (LoopStmtChecker.Visit(S)) { + DepDecl = LoopStmtChecker.getDepDecl(); + return LoopStmtChecker.getBaseLoopId(); + } + return llvm::None; +} + bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { // Check init-expr for canonical loop form and save loop counter // variable - #Var and its initialization value - #LB. @@ -4188,13 +5060,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); - return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); + return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); } } } else if (auto *DS = dyn_cast<DeclStmt>(S)) { @@ -4211,7 +5085,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(), DS->getBeginLoc()), - Var->getInit()); + Var->getInit(), EmitDiags); } } } @@ -4221,13 +5095,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); - return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); + return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); } } } @@ -4581,7 +5457,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond( /*AllowExplicit=*/true); } SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); - // Otherwise use original loop conditon and evaluate it in runtime. + // Otherwise use original loop condition and evaluate it in runtime. return CondExpr.isUsable() ? CondExpr.get() : Cond; } @@ -4602,8 +5478,7 @@ DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar( Captures.insert(std::make_pair(LCRef, Ref)); return Ref; } - return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(), - DefaultLoc); + return cast<DeclRefExpr>(LCRef); } Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const { @@ -4648,10 +5523,12 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower - Expr *Upper = - TestIsLessOp.getValue() ? Cnt : tryBuildCapture(SemaRef, UB, Captures).get(); - Expr *Lower = - TestIsLessOp.getValue() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt; + Expr *Upper = TestIsLessOp.getValue() + ? Cnt + : tryBuildCapture(SemaRef, UB, Captures).get(); + Expr *Lower = TestIsLessOp.getValue() + ? tryBuildCapture(SemaRef, LB, Captures).get() + : Cnt; if (!Upper || !Lower) return nullptr; @@ -4687,6 +5564,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( /// Iteration space of a single for loop. struct LoopIterationSpace final { + /// True if the condition operator is the strict compare operator (<, > or + /// !=). + bool IsStrictCompare = false; /// Condition of the loop. Expr *PreCond = nullptr; /// This expression calculates the number of iterations in the loop. @@ -4720,7 +5600,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { DSAStack->loopStart(); - OpenMPIterationSpaceChecker ISC(*this, ForLoc); + OpenMPIterationSpaceChecker ISC(*this, *DSAStack, ForLoc); if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast<VarDecl>(D); @@ -4786,7 +5666,7 @@ static bool checkOpenMPIterationSpace( } assert(For->getBody()); - OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc()); + OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc()); // Check init. Stmt *Init = For->getInit(); @@ -4840,12 +5720,14 @@ static bool checkOpenMPIterationSpace( ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) : OMPC_private; if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind) || + DVar.CKind != PredeterminedCKind && DVar.RefExpr && + (SemaRef.getLangOpts().OpenMP <= 45 || + (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) || ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || isOpenMPDistributeDirective(DKind)) && !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { + (DVar.CKind != OMPC_private || DVar.RefExpr)) { SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(PredeterminedCKind); @@ -4859,10 +5741,7 @@ static bool checkOpenMPIterationSpace( // lastprivate (for simd directives with several collapsed or ordered // loops). if (DVar.CKind == OMPC_unknown) - DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate, - [](OpenMPDirectiveKind) -> bool { return true; }, - /*FromParent=*/false); - DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); + DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); } assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); @@ -4893,6 +5772,7 @@ static bool checkOpenMPIterationSpace( ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange(); ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange(); ResultIterSpace.Subtract = ISC.shouldSubtractStep(); + ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp(); HasErrors |= (ResultIterSpace.PreCond == nullptr || ResultIterSpace.NumIterations == nullptr || @@ -5117,14 +5997,21 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (CollapseLoopCountExpr) { // Found 'collapse' clause - calculate collapse number. Expr::EvalResult Result; - if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) + if (!CollapseLoopCountExpr->isValueDependent() && + CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) { NestedLoopCount = Result.Val.getInt().getLimitedValue(); + } else { + Built.clear(/*Size=*/1); + return 1; + } } unsigned OrderedLoopCount = 1; if (OrderedLoopCountExpr) { // Found 'ordered' clause - calculate collapse number. Expr::EvalResult EVResult; - if (OrderedLoopCountExpr->EvaluateAsInt(EVResult, SemaRef.getASTContext())) { + if (!OrderedLoopCountExpr->isValueDependent() && + OrderedLoopCountExpr->EvaluateAsInt(EVResult, + SemaRef.getASTContext())) { llvm::APSInt Result = EVResult.Val.getInt(); if (Result.getLimitedValue() < NestedLoopCount) { SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), @@ -5135,13 +6022,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, << CollapseLoopCountExpr->getSourceRange(); } OrderedLoopCount = Result.getLimitedValue(); + } else { + Built.clear(/*Size=*/1); + return 1; } } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). llvm::MapVector<const Expr *, DeclRefExpr *> Captures; - SmallVector<LoopIterationSpace, 4> IterSpaces; - IterSpaces.resize(std::max(OrderedLoopCount, NestedLoopCount)); + SmallVector<LoopIterationSpace, 4> IterSpaces( + std::max(OrderedLoopCount, NestedLoopCount)); Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { if (checkOpenMPIterationSpace( @@ -5447,25 +6337,55 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } } - // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. + bool UseStrictCompare = + RealVType->hasUnsignedIntegerRepresentation() && + llvm::all_of(IterSpaces, [](const LoopIterationSpace &LIS) { + return LIS.IsStrictCompare; + }); + // Loop condition (IV < NumIterations) or (IV <= UB or IV < UB + 1 (for + // unsigned IV)) for worksharing loops. SourceLocation CondLoc = AStmt->getBeginLoc(); + Expr *BoundUB = UB.get(); + if (UseStrictCompare) { + BoundUB = + SemaRef + .BuildBinOp(CurScope, CondLoc, BO_Add, BoundUB, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) + .get(); + BoundUB = + SemaRef.ActOnFinishFullExpr(BoundUB, /*DiscardedValue*/ false).get(); + } ExprResult Cond = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) - ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) + ? SemaRef.BuildBinOp(CurScope, CondLoc, + UseStrictCompare ? BO_LT : BO_LE, IV.get(), + BoundUB) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); ExprResult CombDistCond; if (isOpenMPLoopBoundSharingDirective(DKind)) { - CombDistCond = - SemaRef.BuildBinOp( - CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); + CombDistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), + NumIterations.get()); } ExprResult CombCond; if (isOpenMPLoopBoundSharingDirective(DKind)) { + Expr *BoundCombUB = CombUB.get(); + if (UseStrictCompare) { + BoundCombUB = + SemaRef + .BuildBinOp( + CurScope, CondLoc, BO_Add, BoundCombUB, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) + .get(); + BoundCombUB = + SemaRef.ActOnFinishFullExpr(BoundCombUB, /*DiscardedValue*/ false) + .get(); + } CombCond = - SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get()); + SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, + IV.get(), BoundCombUB); } // Loop increment (IV = IV + 1) SourceLocation IncLoc = AStmt->getBeginLoc(); @@ -5542,7 +6462,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation DistIncLoc = AStmt->getBeginLoc(); ExprResult DistCond, DistInc, PrevEUB, ParForInDistCond; if (isOpenMPLoopBoundSharingDirective(DKind)) { - DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()); + DistCond = SemaRef.BuildBinOp( + CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, IV.get(), BoundUB); assert(DistCond.isUsable() && "distribute cond expr was not built"); DistInc = @@ -5566,10 +6487,24 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, PrevEUB = SemaRef.ActOnFinishFullExpr(PrevEUB.get(), /*DiscardedValue*/ false); - // Build IV <= PrevUB to be used in parallel for is in combination with - // a distribute directive with schedule(static, 1) + // Build IV <= PrevUB or IV < PrevUB + 1 for unsigned IV to be used in + // parallel for is in combination with a distribute directive with + // schedule(static, 1) + Expr *BoundPrevUB = PrevUB.get(); + if (UseStrictCompare) { + BoundPrevUB = + SemaRef + .BuildBinOp( + CurScope, CondLoc, BO_Add, BoundPrevUB, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) + .get(); + BoundPrevUB = + SemaRef.ActOnFinishFullExpr(BoundPrevUB, /*DiscardedValue*/ false) + .get(); + } ParForInDistCond = - SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), PrevUB.get()); + SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, + IV.get(), BoundPrevUB); } // Build updates and final values of the loop counters. @@ -7015,7 +7950,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, auto I = CS->body_begin(); while (I != CS->body_end()) { const auto *OED = dyn_cast<OMPExecutableDirective>(*I); - if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) { + if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind()) || + OMPTeamsFound) { + OMPTeamsFound = false; break; } @@ -8235,6 +9172,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_simdlen: Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_allocator: + Res = ActOnOpenMPAllocatorClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_collapse: Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -8281,6 +9221,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -8365,12 +9306,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( // Do not capture if-clause expressions. break; case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8431,12 +9374,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskloop: case OMPD_taskloop_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8498,12 +9443,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8562,12 +9509,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8627,12 +9576,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel: case OMPD_parallel_sections: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8691,12 +9642,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel: case OMPD_parallel_sections: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8754,12 +9707,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8793,6 +9748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_final: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_private: case OMPC_shared: @@ -8804,6 +9760,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -9042,6 +9999,71 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc, OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc); } +/// Tries to find omp_allocator_handle_t type. +static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, + DSAStackTy *Stack) { + QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT(); + if (!OMPAllocatorHandleT.isNull()) + return true; + // Build the predefined allocator expressions. + bool ErrorFound = false; + for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; + I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); + StringRef Allocator = + OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind); + DeclarationName AllocatorName = &S.getASTContext().Idents.get(Allocator); + auto *VD = dyn_cast_or_null<ValueDecl>( + S.LookupSingleName(S.TUScope, AllocatorName, Loc, Sema::LookupAnyName)); + if (!VD) { + ErrorFound = true; + break; + } + QualType AllocatorType = + VD->getType().getNonLValueExprType(S.getASTContext()); + ExprResult Res = S.BuildDeclRefExpr(VD, AllocatorType, VK_LValue, Loc); + if (!Res.isUsable()) { + ErrorFound = true; + break; + } + if (OMPAllocatorHandleT.isNull()) + OMPAllocatorHandleT = AllocatorType; + if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) { + ErrorFound = true; + break; + } + Stack->setAllocator(AllocatorKind, Res.get()); + } + if (ErrorFound) { + S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found); + return false; + } + OMPAllocatorHandleT.addConst(); + Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT); + return true; +} + +OMPClause *Sema::ActOnOpenMPAllocatorClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + // OpenMP [2.11.3, allocate Directive, Description] + // allocator is an expression of omp_allocator_handle_t type. + if (!findOMPAllocatorHandleT(*this, A->getExprLoc(), DSAStack)) + return nullptr; + + ExprResult Allocator = DefaultLvalueConversion(A); + if (Allocator.isInvalid()) + return nullptr; + Allocator = PerformImplicitConversion(Allocator.get(), + DSAStack->getOMPAllocatorHandleT(), + Sema::AA_Initializing, + /*AllowExplicit=*/true); + if (Allocator.isInvalid()) + return nullptr; + return new (Context) + OMPAllocatorClause(Allocator.get(), StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9109,6 +10131,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_schedule: case OMPC_private: @@ -9127,6 +10150,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -9285,6 +10309,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: @@ -9304,6 +10329,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -9505,6 +10531,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_schedule: case OMPC_private: @@ -9521,6 +10548,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_default: case OMPC_proc_bind: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_depend: case OMPC_device: @@ -9623,14 +10651,16 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, - SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, - SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, + const OMPVarListLocTy &Locs, SourceLocation ColonLoc, + CXXScopeSpec &ReductionOrMapperIdScopeSpec, + DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind, OpenMPLinearClauseKind LinKind, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, - ArrayRef<SourceLocation> MapTypeModifiersLoc, - OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, - SourceLocation DepLinMapLoc) { + ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType, + bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) { + SourceLocation StartLoc = Locs.StartLoc; + SourceLocation LParenLoc = Locs.LParenLoc; + SourceLocation EndLoc = Locs.EndLoc; OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: @@ -9647,17 +10677,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( break; case OMPC_reduction: Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, ReductionId); + EndLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId); break; case OMPC_task_reduction: Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, - ReductionId); + EndLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId); break; case OMPC_in_reduction: - Res = - ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, ReductionId); + Res = ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, + EndLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId); break; case OMPC_linear: Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, @@ -9681,27 +10712,35 @@ OMPClause *Sema::ActOnOpenMPVarListClause( StartLoc, LParenLoc, EndLoc); break; case OMPC_map: - Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, MapType, - IsMapTypeImplicit, DepLinMapLoc, ColonLoc, - VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, + ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, MapType, IsMapTypeImplicit, + DepLinMapLoc, ColonLoc, VarList, Locs); break; case OMPC_to: - Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, Locs); break; case OMPC_from: - Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPFromClause(VarList, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, Locs); break; case OMPC_use_device_ptr: - Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs); break; case OMPC_is_device_ptr: - Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); + break; + case OMPC_allocate: + Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, + ColonLoc, EndLoc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: @@ -9759,66 +10798,6 @@ ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, return Res; } -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); - - // 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)) { - Expr *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)) { - Expr *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()))) { - 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( - getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); -} - OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -10511,8 +11490,8 @@ public: } // namespace template <typename T, typename U> -static T filterLookupForUDR(SmallVectorImpl<U> &Lookups, - const llvm::function_ref<T(ValueDecl *)> Gen) { +static T filterLookupForUDReductionAndMapper( + SmallVectorImpl<U> &Lookups, const llvm::function_ref<T(ValueDecl *)> Gen) { for (U &Set : Lookups) { for (auto *D : Set) { if (T Res = Gen(cast<ValueDecl>(D))) @@ -10539,7 +11518,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { } static void -argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId, +argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &Id, SourceLocation Loc, QualType Ty, SmallVectorImpl<UnresolvedSet<8>> &Lookups) { // Find all of the associated namespaces and classes based on the @@ -10573,13 +11552,14 @@ argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId, // associated classes are visible within their respective // namespaces even if they are not visible during an ordinary // lookup (11.4). - DeclContext::lookup_result R = NS->lookup(ReductionId.getName()); + DeclContext::lookup_result R = NS->lookup(Id.getName()); for (auto *D : R) { auto *Underlying = D; if (auto *USD = dyn_cast<UsingShadowDecl>(D)) Underlying = USD->getTargetDecl(); - if (!isa<OMPDeclareReductionDecl>(Underlying)) + if (!isa<OMPDeclareReductionDecl>(Underlying) && + !isa<OMPDeclareMapperDecl>(Underlying)) continue; if (!SemaRef.isVisible(D)) { @@ -10624,7 +11604,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, for (NamedDecl *D : ULE->decls()) { if (D == PrevD) Lookups.push_back(UnresolvedSet<8>()); - else if (auto *DRD = cast<OMPDeclareReductionDecl>(D)) + else if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(D)) Lookups.back().addDecl(DRD); PrevD = D; } @@ -10632,7 +11612,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() || Ty->isInstantiationDependentType() || Ty->containsUnexpandedParameterPack() || - filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) { + filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) { return !D->isInvalidDecl() && (D->getType()->isDependentType() || D->getType()->isInstantiationDependentType() || @@ -10680,33 +11660,38 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, } } // Perform ADL. - argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups); - if (auto *VD = filterLookupForUDR<ValueDecl *>( + if (SemaRef.getLangOpts().CPlusPlus) + argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups); + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.Context.hasSameType(D->getType(), Ty)) return D; return nullptr; })) - return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); - if (auto *VD = filterLookupForUDR<ValueDecl *>( - Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { - if (!D->isInvalidDecl() && - SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && - !Ty.isMoreQualifiedThan(D->getType())) - return D; - return nullptr; - })) { - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) { - if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( - VD->getType().getUnqualifiedType()))) { - if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(), - /*DiagID=*/0) != - Sema::AR_inaccessible) { - SemaRef.BuildBasePathArray(Paths, BasePath); - return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); + return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), + VK_LValue, Loc); + if (SemaRef.getLangOpts().CPlusPlus) { + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( + Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && + !Ty.isMoreQualifiedThan(D->getType())) + return D; + return nullptr; + })) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) { + if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( + VD->getType().getUnqualifiedType()))) { + if (SemaRef.CheckBaseClassAccess( + Loc, VD->getType(), Ty, Paths.front(), + /*DiagID=*/0) != Sema::AR_inaccessible) { + SemaRef.BuildBasePathArray(Paths, BasePath); + return SemaRef.BuildDeclRefExpr( + VD, VD->getType().getNonReferenceType(), VK_LValue, Loc); + } } } } @@ -11156,10 +12141,14 @@ static bool actOnOMPReductionKindClause( if ((OASE && !ConstantLengthOASE) || (!OASE && !ASE && D->getType().getNonReferenceType()->isVariablyModifiedType())) { - if (!Context.getTargetInfo().isVLASupported() && - S.shouldDiagnoseTargetSupportFromOpenMP()) { - S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; - S.Diag(ELoc, diag::note_vla_unsupported); + if (!Context.getTargetInfo().isVLASupported()) { + if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) { + S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; + S.Diag(ELoc, diag::note_vla_unsupported); + } else { + S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; + S.targetDiag(ELoc, diag::note_vla_unsupported); + } continue; } // For arrays/array sections only: @@ -11300,7 +12289,8 @@ static bool actOnOMPReductionKindClause( S.ActOnUninitializedDecl(RHSVD); if (RHSVD->isInvalidDecl()) continue; - if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) { + if (!RHSVD->hasInit() && + (DeclareReductionRef.isUnset() || !S.LangOpts.CPlusPlus)) { S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == @@ -12885,6 +13875,110 @@ static bool checkMapConflicts( return FoundError; } +// Look up the user-defined mapper given the mapper name and mapped type, and +// build a reference to it. +static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, + CXXScopeSpec &MapperIdScopeSpec, + const DeclarationNameInfo &MapperId, + QualType Type, + Expr *UnresolvedMapper) { + if (MapperIdScopeSpec.isInvalid()) + return ExprError(); + // Find all user-defined mappers with the given MapperId. + SmallVector<UnresolvedSet<8>, 4> Lookups; + LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName); + Lookup.suppressDiagnostics(); + if (S) { + while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) { + NamedDecl *D = Lookup.getRepresentativeDecl(); + while (S && !S->isDeclScope(D)) + S = S->getParent(); + if (S) + S = S->getParent(); + Lookups.emplace_back(); + Lookups.back().append(Lookup.begin(), Lookup.end()); + Lookup.clear(); + } + } else if (auto *ULE = cast_or_null<UnresolvedLookupExpr>(UnresolvedMapper)) { + // Extract the user-defined mappers with the given MapperId. + Lookups.push_back(UnresolvedSet<8>()); + for (NamedDecl *D : ULE->decls()) { + auto *DMD = cast<OMPDeclareMapperDecl>(D); + assert(DMD && "Expect valid OMPDeclareMapperDecl during instantiation."); + Lookups.back().addDecl(DMD); + } + } + // Defer the lookup for dependent types. The results will be passed through + // UnresolvedMapper on instantiation. + if (SemaRef.CurContext->isDependentContext() || Type->isDependentType() || + Type->isInstantiationDependentType() || + Type->containsUnexpandedParameterPack() || + filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) { + return !D->isInvalidDecl() && + (D->getType()->isDependentType() || + D->getType()->isInstantiationDependentType() || + D->getType()->containsUnexpandedParameterPack()); + })) { + UnresolvedSet<8> URS; + for (const UnresolvedSet<8> &Set : Lookups) { + if (Set.empty()) + continue; + URS.append(Set.begin(), Set.end()); + } + return UnresolvedLookupExpr::Create( + SemaRef.Context, /*NamingClass=*/nullptr, + MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId, + /*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end()); + } + // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions + // The type must be of struct, union or class type in C and C++ + if (!Type->isStructureOrClassType() && !Type->isUnionType()) + return ExprEmpty(); + SourceLocation Loc = MapperId.getLoc(); + // Perform argument dependent lookup. + if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet()) + argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups); + // Return the first user-defined mapper with the desired type. + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( + Lookups, [&SemaRef, Type](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.Context.hasSameType(D->getType(), Type)) + return D; + return nullptr; + })) + return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc); + // Find the first user-defined mapper with a type derived from the desired + // type. + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( + Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.IsDerivedFrom(Loc, Type, D->getType()) && + !Type.isMoreQualifiedThan(D->getType())) + return D; + return nullptr; + })) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(Loc, Type, VD->getType(), Paths)) { + if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( + VD->getType().getUnqualifiedType()))) { + if (SemaRef.CheckBaseClassAccess( + Loc, VD->getType(), Type, Paths.front(), + /*DiagID=*/0) != Sema::AR_inaccessible) { + return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc); + } + } + } + } + // Report error if a mapper is specified, but cannot be found. + if (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default") { + SemaRef.Diag(Loc, diag::err_omp_invalid_mapper) + << Type << MapperId.getName(); + return ExprError(); + } + return ExprEmpty(); +} + namespace { // Utility struct that gathers all the related lists associated with a mappable // expression. @@ -12897,6 +13991,8 @@ struct MappableVarListInfo { OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents; // The base declaration of the variable. SmallVector<ValueDecl *, 16> VarBaseDeclarations; + // The reference to the user-defined mapper associated with every expression. + SmallVector<Expr *, 16> UDMapperList; MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) { // We have a list of components and base declarations for each entry in the @@ -12908,20 +14004,37 @@ struct MappableVarListInfo { } // Check the validity of the provided variable list for the provided clause kind -// \a CKind. In the check process the valid expressions, and mappable expression -// components and variables are extracted and used to fill \a Vars, -// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and -// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'. -static void -checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, - OpenMPClauseKind CKind, MappableVarListInfo &MVLI, - SourceLocation StartLoc, - OpenMPMapClauseKind MapType = OMPC_MAP_unknown, - bool IsMapTypeImplicit = false) { +// \a CKind. In the check process the valid expressions, mappable expression +// components, variables, and user-defined mappers are extracted and used to +// fill \a ProcessedVarList, \a VarComponents, \a VarBaseDeclarations, and \a +// UDMapperList in MVLI. \a MapType, \a IsMapTypeImplicit, \a MapperIdScopeSpec, +// and \a MapperId are expected to be valid if the clause kind is 'map'. +static void checkMappableExpressionList( + Sema &SemaRef, DSAStackTy *DSAS, OpenMPClauseKind CKind, + MappableVarListInfo &MVLI, SourceLocation StartLoc, + CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId, + ArrayRef<Expr *> UnresolvedMappers, + OpenMPMapClauseKind MapType = OMPC_MAP_unknown, + bool IsMapTypeImplicit = false) { // We only expect mappable expressions in 'to', 'from', and 'map' clauses. assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && "Unexpected clause kind with mappable expressions!"); + // If the identifier of user-defined mapper is not specified, it is "default". + // We do not change the actual name in this clause to distinguish whether a + // mapper is specified explicitly, i.e., it is not explicitly specified when + // MapperId.getName() is empty. + if (!MapperId.getName() || MapperId.getName().isEmpty()) { + auto &DeclNames = SemaRef.getASTContext().DeclarationNames; + MapperId.setName(DeclNames.getIdentifier( + &SemaRef.getASTContext().Idents.get("default"))); + } + + // Iterators to find the current unresolved mapper expression. + auto UMIt = UnresolvedMappers.begin(), UMEnd = UnresolvedMappers.end(); + bool UpdateUMIt = false; + Expr *UnresolvedMapper = nullptr; + // Keep track of the mappable components and base declarations in this clause. // Each entry in the list is going to have a list of components associated. We // record each set of the components so that we can build the clause later on. @@ -12932,11 +14045,29 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, assert(RE && "Null expr in omp to/from/map clause"); SourceLocation ELoc = RE->getExprLoc(); + // Find the current unresolved mapper expression. + if (UpdateUMIt && UMIt != UMEnd) { + UMIt++; + assert( + UMIt != UMEnd && + "Expect the size of UnresolvedMappers to match with that of VarList"); + } + UpdateUMIt = true; + if (UMIt != UMEnd) + UnresolvedMapper = *UMIt; + const Expr *VE = RE->IgnoreParenLValueCasts(); if (VE->isValueDependent() || VE->isTypeDependent() || VE->isInstantiationDependent() || VE->containsUnexpandedParameterPack()) { + // Try to find the associated user-defined mapper. + ExprResult ER = buildUserDefinedMapperRef( + SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId, + VE->getType().getCanonicalType(), UnresolvedMapper); + if (ER.isInvalid()) + continue; + MVLI.UDMapperList.push_back(ER.get()); // We can only analyze this information once the missing information is // resolved. MVLI.ProcessedVarList.push_back(RE); @@ -12968,6 +14099,13 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, if (const auto *TE = dyn_cast<CXXThisExpr>(BE)) { // Add store "this" pointer to class in DSAStackTy for future checking DSAS->addMappedClassesQualTypes(TE->getType()); + // Try to find the associated user-defined mapper. + ExprResult ER = buildUserDefinedMapperRef( + SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId, + VE->getType().getCanonicalType(), UnresolvedMapper); + if (ER.isInvalid()) + continue; + MVLI.UDMapperList.push_back(ER.get()); // Skip restriction checking for variable or field declarations MVLI.ProcessedVarList.push_back(RE); MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1); @@ -13086,6 +14224,14 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, } } + // Try to find the associated user-defined mapper. + ExprResult ER = buildUserDefinedMapperRef( + SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId, + Type.getCanonicalType(), UnresolvedMapper); + if (ER.isInvalid()) + continue; + MVLI.UDMapperList.push_back(ER.get()); + // Save the current expression. MVLI.ProcessedVarList.push_back(RE); @@ -13105,19 +14251,16 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, } } -OMPClause * -Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, - ArrayRef<SourceLocation> MapTypeModifiersLoc, - OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, - SourceLocation MapLoc, SourceLocation ColonLoc, - ArrayRef<Expr *> VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { - MappableVarListInfo MVLI(VarList); - checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc, - MapType, IsMapTypeImplicit); - - OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown, - OMPC_MAP_MODIFIER_unknown }; +OMPClause *Sema::ActOnOpenMPMapClause( + ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, + ArrayRef<SourceLocation> MapTypeModifiersLoc, + CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) { + OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown, + OMPC_MAP_MODIFIER_unknown, + OMPC_MAP_MODIFIER_unknown}; SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers]; // Process map-type-modifiers, flag errors for duplicate modifiers. @@ -13135,12 +14278,18 @@ Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, ++Count; } + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, Locs.StartLoc, + MapperIdScopeSpec, MapperId, UnresolvedMappers, + MapType, IsMapTypeImplicit); + // We need to produce a map clause even if we don't have variables so that // other diagnostics related with non-existing map clauses are accurate. - return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, - MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, - MVLI.VarComponents, Modifiers, ModifiersLoc, - MapType, IsMapTypeImplicit, MapLoc); + return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, MVLI.VarComponents, + MVLI.UDMapperList, Modifiers, ModifiersLoc, + MapperIdScopeSpec.getWithLocInContext(Context), + MapperId, MapType, IsMapTypeImplicit, MapLoc); } QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, @@ -13400,6 +14549,143 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( return DeclReductions; } +TypeResult Sema::ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D) { + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType T = TInfo->getType(); + if (D.isInvalidType()) + return true; + + if (getLangOpts().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + return CreateParsedType(T, TInfo); +} + +QualType Sema::ActOnOpenMPDeclareMapperType(SourceLocation TyLoc, + TypeResult ParsedType) { + assert(ParsedType.isUsable() && "Expect usable parsed mapper type"); + + QualType MapperType = GetTypeFromParser(ParsedType.get()); + assert(!MapperType.isNull() && "Expect valid mapper type"); + + // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions + // The type must be of struct, union or class type in C and C++ + if (!MapperType->isStructureOrClassType() && !MapperType->isUnionType()) { + Diag(TyLoc, diag::err_omp_mapper_wrong_type); + return QualType(); + } + return MapperType; +} + +OMPDeclareMapperDecl *Sema::ActOnOpenMPDeclareMapperDirectiveStart( + Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType, + SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS, + Decl *PrevDeclInScope) { + LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPMapperName, + forRedeclarationInCurContext()); + // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions + // A mapper-identifier may not be redeclared in the current scope for the + // same type or for a type that is compatible according to the base language + // rules. + llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes; + OMPDeclareMapperDecl *PrevDMD = nullptr; + bool InCompoundScope = true; + if (S != nullptr) { + // Find previous declaration with the same name not referenced in other + // declarations. + FunctionScopeInfo *ParentFn = getEnclosingFunction(); + InCompoundScope = + (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty(); + LookupName(Lookup, S); + FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + llvm::DenseMap<OMPDeclareMapperDecl *, bool> UsedAsPrevious; + LookupResult::Filter Filter = Lookup.makeFilter(); + while (Filter.hasNext()) { + auto *PrevDecl = cast<OMPDeclareMapperDecl>(Filter.next()); + if (InCompoundScope) { + auto I = UsedAsPrevious.find(PrevDecl); + if (I == UsedAsPrevious.end()) + UsedAsPrevious[PrevDecl] = false; + if (OMPDeclareMapperDecl *D = PrevDecl->getPrevDeclInScope()) + UsedAsPrevious[D] = true; + } + PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] = + PrevDecl->getLocation(); + } + Filter.done(); + if (InCompoundScope) { + for (const auto &PrevData : UsedAsPrevious) { + if (!PrevData.second) { + PrevDMD = PrevData.first; + break; + } + } + } + } else if (PrevDeclInScope) { + auto *PrevDMDInScope = PrevDMD = + cast<OMPDeclareMapperDecl>(PrevDeclInScope); + do { + PreviousRedeclTypes[PrevDMDInScope->getType().getCanonicalType()] = + PrevDMDInScope->getLocation(); + PrevDMDInScope = PrevDMDInScope->getPrevDeclInScope(); + } while (PrevDMDInScope != nullptr); + } + const auto I = PreviousRedeclTypes.find(MapperType.getCanonicalType()); + bool Invalid = false; + if (I != PreviousRedeclTypes.end()) { + Diag(StartLoc, diag::err_omp_declare_mapper_redefinition) + << MapperType << Name; + Diag(I->second, diag::note_previous_definition); + Invalid = true; + } + auto *DMD = OMPDeclareMapperDecl::Create(Context, DC, StartLoc, Name, + MapperType, VN, PrevDMD); + DC->addDecl(DMD); + DMD->setAccess(AS); + if (Invalid) + DMD->setInvalidDecl(); + + // Enter new function scope. + PushFunctionScope(); + setFunctionHasBranchProtectedScope(); + + CurContext = DMD; + + return DMD; +} + +void Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD, + Scope *S, + QualType MapperType, + SourceLocation StartLoc, + DeclarationName VN) { + VarDecl *VD = buildVarDecl(*this, StartLoc, MapperType, VN.getAsString()); + if (S) + PushOnScopeChains(VD, S); + else + DMD->addDecl(VD); + Expr *MapperVarRefExpr = buildDeclRefExpr(*this, VD, MapperType, StartLoc); + DMD->setMapperVarRef(MapperVarRefExpr); +} + +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S, + ArrayRef<OMPClause *> ClauseList) { + PopDeclContext(); + PopFunctionScopeInfo(); + + if (D) { + if (S) + PushOnScopeChains(D, S, /*AddToContext=*/false); + D->CreateClauses(Context, ClauseList); + } + + return DeclGroupPtrTy::make(DeclGroupRef(D)); +} + OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -13632,9 +14918,9 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, Lookup.suppressDiagnostics(); if (!Lookup.isSingleResult()) { + VarOrFuncDeclFilterCCC CCC(*this); if (TypoCorrection Corrected = - CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, - llvm::make_unique<VarOrFuncDeclFilterCCC>(*this), + CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC, CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Id.getName()); @@ -13744,37 +15030,41 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, } OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, + const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers) { MappableVarListInfo MVLI(VarList); - checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc); + checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, Locs.StartLoc, + MapperIdScopeSpec, MapperId, UnresolvedMappers); if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc, - MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, - MVLI.VarComponents); + return OMPToClause::Create( + Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MVLI.UDMapperList, + MapperIdScopeSpec.getWithLocInContext(Context), MapperId); } OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, + const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers) { MappableVarListInfo MVLI(VarList); - checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc); + checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, Locs.StartLoc, + MapperIdScopeSpec, MapperId, UnresolvedMappers); if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc, - MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, - MVLI.VarComponents); + return OMPFromClause::Create( + Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MVLI.UDMapperList, + MapperIdScopeSpec.getWithLocInContext(Context), MapperId); } OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); SmallVector<Expr *, 8> PrivateCopies; SmallVector<Expr *, 8> Inits; @@ -13854,14 +15144,12 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, return nullptr; return OMPUseDevicePtrClause::Create( - Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList, - PrivateCopies, Inits, MVLI.VarBaseDeclarations, MVLI.VarComponents); + Context, Locs, MVLI.ProcessedVarList, PrivateCopies, Inits, + MVLI.VarBaseDeclarations, MVLI.VarComponents); } OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause."); @@ -13937,7 +15225,68 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPIsDevicePtrClause::Create( - Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList, - MVLI.VarBaseDeclarations, MVLI.VarComponents); + return OMPIsDevicePtrClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + +OMPClause *Sema::ActOnOpenMPAllocateClause( + Expr *Allocator, ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { + if (Allocator) { + // OpenMP [2.11.4 allocate Clause, Description] + // allocator is an expression of omp_allocator_handle_t type. + if (!findOMPAllocatorHandleT(*this, Allocator->getExprLoc(), DSAStack)) + return nullptr; + + ExprResult AllocatorRes = DefaultLvalueConversion(Allocator); + if (AllocatorRes.isInvalid()) + return nullptr; + AllocatorRes = PerformImplicitConversion(AllocatorRes.get(), + DSAStack->getOMPAllocatorHandleT(), + Sema::AA_Initializing, + /*AllowExplicit=*/true); + if (AllocatorRes.isInvalid()) + return nullptr; + Allocator = AllocatorRes.get(); + } else { + // OpenMP 5.0, 2.11.4 allocate Clause, Restrictions. + // allocate clauses that appear on a target construct or on constructs in a + // target region must specify an allocator expression unless a requires + // directive with the dynamic_allocators clause is present in the same + // compilation unit. + if (LangOpts.OpenMPIsDevice && + !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>()) + targetDiag(StartLoc, diag::err_expected_allocator_expression); + } + // Analyze and build list of variables. + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP private clause."); + 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); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + auto *VD = dyn_cast<VarDecl>(D); + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); + } + + if (Vars.empty()) + return nullptr; + + return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator, + ColonLoc, EndLoc, Vars); } |