r315005 - Fix two-phase name lookup for non-dependent overloaded operators.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 5 12:35:51 PDT 2017


Author: rsmith
Date: Thu Oct  5 12:35:51 2017
New Revision: 315005

URL: http://llvm.org/viewvc/llvm-project?rev=315005&view=rev
Log:
Fix two-phase name lookup for non-dependent overloaded operators.

If we resolve an overloaded operator call to a specific function during
template definition, don't perform ADL during template instantiation.
Doing so finds overloads that we're not supposed to find.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=315005&r1=315004&r2=315005&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Oct  5 12:35:51 2017
@@ -2914,12 +2914,13 @@ public:
   ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
                                      UnaryOperatorKind Opc,
                                      const UnresolvedSetImpl &Fns,
-                                     Expr *input);
+                                     Expr *input, bool RequiresADL = true);
 
   ExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
                                    BinaryOperatorKind Opc,
                                    const UnresolvedSetImpl &Fns,
-                                   Expr *LHS, Expr *RHS);
+                                   Expr *LHS, Expr *RHS,
+                                   bool RequiresADL = true);
 
   ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
                                                 SourceLocation RLoc,

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=315005&r1=315004&r2=315005&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Oct  5 12:35:51 2017
@@ -11927,7 +11927,7 @@ static bool IsOverloaded(const Unresolve
 ExprResult
 Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
                               const UnresolvedSetImpl &Fns,
-                              Expr *Input) {
+                              Expr *Input, bool PerformADL) {
   OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
   assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
   DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -11978,9 +11978,11 @@ Sema::CreateOverloadedUnaryOp(SourceLoca
   AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
 
   // Add candidates from ADL.
-  AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
-                                       /*ExplicitTemplateArgs*/nullptr,
-                                       CandidateSet);
+  if (PerformADL) {
+    AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+                                         /*ExplicitTemplateArgs*/nullptr,
+                                         CandidateSet);
+  }
 
   // Add builtin operator candidates.
   AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -12118,7 +12120,7 @@ ExprResult
 Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
                             BinaryOperatorKind Opc,
                             const UnresolvedSetImpl &Fns,
-                            Expr *LHS, Expr *RHS) {
+                            Expr *LHS, Expr *RHS, bool PerformADL) {
   Expr *Args[2] = { LHS, RHS };
   LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
 
@@ -12149,7 +12151,7 @@ Sema::CreateOverloadedBinOp(SourceLocati
     UnresolvedLookupExpr *Fn
       = UnresolvedLookupExpr::Create(Context, NamingClass,
                                      NestedNameSpecifierLoc(), OpNameInfo,
-                                     /*ADL*/ true, IsOverloaded(Fns),
+                                     /*ADL*/PerformADL, IsOverloaded(Fns),
                                      Fns.begin(), Fns.end());
     return new (Context)
         CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
@@ -12192,7 +12194,7 @@ Sema::CreateOverloadedBinOp(SourceLocati
   // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
   // performed for an assignment operator (nor for operator[] nor operator->,
   // which don't get here).
-  if (Opc != BO_Assign)
+  if (Opc != BO_Assign && PerformADL)
     AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
                                          /*ExplicitTemplateArgs*/ nullptr,
                                          CandidateSet);

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=315005&r1=315004&r2=315005&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Oct  5 12:35:51 2017
@@ -12636,10 +12636,14 @@ TreeTransform<Derived>::RebuildCXXOperat
   // Compute the transformed set of functions (and function templates) to be
   // used during overload resolution.
   UnresolvedSet<16> Functions;
+  bool RequiresADL;
 
   if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
-    assert(ULE->requiresADL());
     Functions.append(ULE->decls_begin(), ULE->decls_end());
+    // If the overload could not be resolved in the template definition
+    // (because we had a dependent argument), ADL is performed as part of
+    // template instantiation.
+    RequiresADL = ULE->requiresADL();
   } else {
     // If we've resolved this to a particular non-member function, just call
     // that function. If we resolved it to a member function,
@@ -12647,6 +12651,7 @@ TreeTransform<Derived>::RebuildCXXOperat
     NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl();
     if (!isa<CXXMethodDecl>(ND))
       Functions.addDecl(ND);
+    RequiresADL = false;
   }
 
   // Add any functions found via argument-dependent lookup.
@@ -12657,7 +12662,8 @@ TreeTransform<Derived>::RebuildCXXOperat
   if (NumArgs == 1 || isPostIncDec) {
     UnaryOperatorKind Opc
       = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
-    return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First);
+    return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First,
+                                           RequiresADL);
   }
 
   if (Op == OO_Subscript) {
@@ -12681,8 +12687,8 @@ TreeTransform<Derived>::RebuildCXXOperat
 
   // Create the overloaded operator invocation for binary operators.
   BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
-  ExprResult Result
-    = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]);
+  ExprResult Result = SemaRef.CreateOverloadedBinOp(
+      OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL);
   if (Result.isInvalid())
     return ExprError();
 

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=315005&r1=315004&r2=315005&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Thu Oct  5 12:35:51 2017
@@ -550,3 +550,38 @@ namespace PR27027 {
   bool test_global_1 = +a_global; // expected-error {{overload resolution selected deleted operator '+'}}
   bool test_global_2 = a_global + a_global; // expected-error {{overload resolution selected deleted operator '+'}}
 }
+
+namespace LateADLInNonDependentExpressions {
+  struct A {};
+  struct B : A {};
+  int &operator+(A, A);
+  int &operator!(A);
+  int &operator+=(A, A);
+  int &operator<<(A, A);
+  int &operator++(A);
+  int &operator++(A, int);
+  int &operator->*(A, A);
+
+  template<typename T> void f() {
+    // An instantiation-dependent value of type B.
+    // These are all non-dependent operator calls of type int&.
+#define idB ((void()), B())
+    int &a = idB + idB,
+        &b = !idB,
+        &c = idB += idB,
+        &d = idB << idB,
+        &e = ++idB,
+        &f = idB++,
+        &g = idB ->* idB;
+  }
+
+  // These should not be found by ADL in the template instantiation.
+  float &operator+(B, B);
+  float &operator!(B);
+  float &operator+=(B, B);
+  float &operator<<(B, B);
+  float &operator++(B);
+  float &operator++(B, int);
+  float &operator->*(B, B);
+  template void f<int>();
+}




More information about the cfe-commits mailing list