r342062 - [OPENMP] Fix PR38902: support ADL for declare reduction constructs.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 12 09:31:59 PDT 2018


Author: abataev
Date: Wed Sep 12 09:31:59 2018
New Revision: 342062

URL: http://llvm.org/viewvc/llvm-project?rev=342062&view=rev
Log:
[OPENMP] Fix PR38902: support ADL for declare reduction constructs.

Added support for argument-dependent lookup when trying to find the
required declare reduction decl.

Modified:
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/test/OpenMP/declare_reduction_ast_print.cpp

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=342062&r1=342061&r2=342062&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Wed Sep 12 09:31:59 2018
@@ -10068,6 +10068,79 @@ static T filterLookupForUDR(SmallVectorI
   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,
       } 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,
       })) {
     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,
         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() &&

Modified: cfe/trunk/test/OpenMP/declare_reduction_ast_print.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_reduction_ast_print.cpp?rev=342062&r1=342061&r2=342062&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_reduction_ast_print.cpp (original)
+++ cfe/trunk/test/OpenMP/declare_reduction_ast_print.cpp Wed Sep 12 09:31:59 2018
@@ -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);
 }
 




More information about the cfe-commits mailing list