mirror of https://github.com/microsoft/clang.git
[OPENMP] Fix PR38902: support ADL for declare reduction constructs.
Added support for argument-dependent lookup when trying to find the required declare reduction decl. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@342062 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2e989bf873
commit
cbe41bdb06
|
@ -10068,6 +10068,79 @@ static T filterLookupForUDR(SmallVectorImpl<U> &Lookups,
|
|||
return T();
|
||||
}
|
||||
|
||||
static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
|
||||
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
|
||||
|
||||
for (auto RD : D->redecls()) {
|
||||
// Don't bother with extra checks if we already know this one isn't visible.
|
||||
if (RD == D)
|
||||
continue;
|
||||
|
||||
auto ND = cast<NamedDecl>(RD);
|
||||
if (LookupResult::isVisible(SemaRef, ND))
|
||||
return ND;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId,
|
||||
SourceLocation Loc, QualType Ty,
|
||||
SmallVectorImpl<UnresolvedSet<8>> &Lookups) {
|
||||
// Find all of the associated namespaces and classes based on the
|
||||
// arguments we have.
|
||||
Sema::AssociatedNamespaceSet AssociatedNamespaces;
|
||||
Sema::AssociatedClassSet AssociatedClasses;
|
||||
OpaqueValueExpr OVE(Loc, Ty, VK_LValue);
|
||||
SemaRef.FindAssociatedClassesAndNamespaces(Loc, &OVE, AssociatedNamespaces,
|
||||
AssociatedClasses);
|
||||
|
||||
// C++ [basic.lookup.argdep]p3:
|
||||
// Let X be the lookup set produced by unqualified lookup (3.4.1)
|
||||
// and let Y be the lookup set produced by argument dependent
|
||||
// lookup (defined as follows). If X contains [...] then Y is
|
||||
// empty. Otherwise Y is the set of declarations found in the
|
||||
// namespaces associated with the argument types as described
|
||||
// below. The set of declarations found by the lookup of the name
|
||||
// is the union of X and Y.
|
||||
//
|
||||
// Here, we compute Y and add its members to the overloaded
|
||||
// candidate set.
|
||||
for (auto *NS : AssociatedNamespaces) {
|
||||
// When considering an associated namespace, the lookup is the
|
||||
// same as the lookup performed when the associated namespace is
|
||||
// used as a qualifier (3.4.3.2) except that:
|
||||
//
|
||||
// -- Any using-directives in the associated namespace are
|
||||
// ignored.
|
||||
//
|
||||
// -- Any namespace-scope friend functions declared in
|
||||
// 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());
|
||||
for (auto *D : R) {
|
||||
auto *Underlying = D;
|
||||
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
|
||||
Underlying = USD->getTargetDecl();
|
||||
|
||||
if (!isa<OMPDeclareReductionDecl>(Underlying))
|
||||
continue;
|
||||
|
||||
if (!SemaRef.isVisible(D)) {
|
||||
D = findAcceptableDecl(SemaRef, D);
|
||||
if (!D)
|
||||
continue;
|
||||
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
|
||||
Underlying = USD->getTargetDecl();
|
||||
}
|
||||
Lookups.emplace_back();
|
||||
Lookups.back().addDecl(Underlying);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ExprResult
|
||||
buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
|
||||
Scope *S, CXXScopeSpec &ReductionIdScopeSpec,
|
||||
|
@ -10086,7 +10159,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
|
|||
} while (S && !S->isDeclScope(D));
|
||||
if (S)
|
||||
S = S->getParent();
|
||||
Lookups.push_back(UnresolvedSet<8>());
|
||||
Lookups.emplace_back();
|
||||
Lookups.back().append(Lookup.begin(), Lookup.end());
|
||||
Lookup.clear();
|
||||
}
|
||||
|
@ -10113,6 +10186,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
|
|||
})) {
|
||||
UnresolvedSet<8> ResSet;
|
||||
for (const UnresolvedSet<8> &Set : Lookups) {
|
||||
if (Set.empty())
|
||||
continue;
|
||||
ResSet.append(Set.begin(), Set.end());
|
||||
// The last item marks the end of all declarations at the specified scope.
|
||||
ResSet.addDecl(Set[Set.size() - 1]);
|
||||
|
@ -10122,6 +10197,36 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
|
|||
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
|
||||
/*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end());
|
||||
}
|
||||
// Lookup inside the classes.
|
||||
// C++ [over.match.oper]p3:
|
||||
// For a unary operator @ with an operand of a type whose
|
||||
// cv-unqualified version is T1, and for a binary operator @ with
|
||||
// a left operand of a type whose cv-unqualified version is T1 and
|
||||
// a right operand of a type whose cv-unqualified version is T2,
|
||||
// three sets of candidate functions, designated member
|
||||
// candidates, non-member candidates and built-in candidates, are
|
||||
// constructed as follows:
|
||||
// -- If T1 is a complete class type or a class currently being
|
||||
// defined, the set of member candidates is the result of the
|
||||
// qualified lookup of T1::operator@ (13.3.1.1.1); otherwise,
|
||||
// the set of member candidates is empty.
|
||||
LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
|
||||
Lookup.suppressDiagnostics();
|
||||
if (const auto *TyRec = Ty->getAs<RecordType>()) {
|
||||
// Complete the type if it can be completed.
|
||||
// If the type is neither complete nor being defined, bail out now.
|
||||
if (SemaRef.isCompleteType(Loc, Ty) || TyRec->isBeingDefined() ||
|
||||
TyRec->getDecl()->getDefinition()) {
|
||||
Lookup.clear();
|
||||
SemaRef.LookupQualifiedName(Lookup, TyRec->getDecl());
|
||||
if (Lookup.empty()) {
|
||||
Lookups.emplace_back();
|
||||
Lookups.back().append(Lookup.begin(), Lookup.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Perform ADL.
|
||||
argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups);
|
||||
if (auto *VD = filterLookupForUDR<ValueDecl *>(
|
||||
Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * {
|
||||
if (!D->isInvalidDecl() &&
|
||||
|
|
|
@ -10,6 +10,15 @@
|
|||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
template <typename T>
|
||||
void bar(T &x, T &y) { x.a += y.a; }
|
||||
|
||||
namespace N1
|
||||
{
|
||||
struct A { int a; A() : a(0) {} };
|
||||
#pragma omp declare reduction(+: A : bar(omp_out, omp_in))
|
||||
};
|
||||
|
||||
#pragma omp declare reduction(+ : int, char : omp_out *= omp_in)
|
||||
// CHECK: #pragma omp declare reduction (+ : int : omp_out *= omp_in){{$}}
|
||||
// CHECK-NEXT: #pragma omp declare reduction (+ : char : omp_out *= omp_in)
|
||||
|
@ -66,6 +75,11 @@ int main() {
|
|||
// TODO-CHECK: #pragma omp parallel reduction(::fun: sss)
|
||||
{
|
||||
}
|
||||
N1::A a;
|
||||
// CHECK: #pragma omp parallel reduction(+: a)
|
||||
#pragma omp parallel reduction(+: a)
|
||||
{
|
||||
}
|
||||
return foo(15);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue