]> granicus.if.org Git - clang/commitdiff
Fix two-phase name lookup for non-dependent overloaded operators.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 5 Oct 2017 19:35:51 +0000 (19:35 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 5 Oct 2017 19:35:51 +0000 (19:35 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315005 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaOverload.cpp
lib/Sema/TreeTransform.h
test/SemaCXX/overloaded-operator.cpp

index 80b6978b925f0468f15f64abf2f1530a85b34735..b33f63225cb353579a40eb20784f14fb3a1a4c26 100644 (file)
@@ -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,
index 66b252e1446e0768c97c9789388c9d6d6c943577..0e53ffa83fefceeb6ba6a0caec6db6fb960487a5 100644 (file)
@@ -11927,7 +11927,7 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
 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(SourceLocation OpLoc, UnaryOperatorKind Opc,
   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(SourceLocation OpLoc,
     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(SourceLocation OpLoc,
   // 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);
index a9ecf721db44b741dec420d0d36dfbaddf0befd9..fa582c221354508372a88cef60505ed6fd144826 100644 (file)
@@ -12636,10 +12636,14 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
   // 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>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
     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>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
   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>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
 
   // 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();
 
index 52d0bff3884c0ece3fc661c5f6ff8d66216e416f..dff9350cc984717a12a6240864619f33a5cab8b5 100644 (file)
@@ -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>();
+}