]> granicus.if.org Git - clang/commitdiff
Make incomplete type errors better with enable_if
authorGeorge Burgess IV <george.burgess.iv@gmail.com>
Fri, 25 Sep 2015 17:53:16 +0000 (17:53 +0000)
committerGeorge Burgess IV <george.burgess.iv@gmail.com>
Fri, 25 Sep 2015 17:53:16 +0000 (17:53 +0000)
This patch fixes the order in which we evaluate the different ways that
a function call could be disallowed. Now, if you call a non-overloaded
function with an incomplete type and failing enable_if, we'll prioritize
reporting the more obvious error (use of incomplete type) over reporting
the failing enable_if.

Thanks to Ettore Speziale for the patch!

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

lib/Sema/SemaOverload.cpp
test/SemaCXX/enable_if.cpp

index b03337f7d7f574fa5caf87f7862af2503f969ae4..49d89c86b7b3740ca08f9f84477be2f07d31a0d6 100644 (file)
@@ -11664,16 +11664,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
     FoundDecl = MemExpr->getFoundDecl();
     Qualifier = MemExpr->getQualifier();
     UnbridgedCasts.restore();
-
-    if (const EnableIfAttr *Attr = CheckEnableIf(Method, Args, true)) {
-      Diag(MemExprE->getLocStart(),
-           diag::err_ovl_no_viable_member_function_in_call)
-          << Method << Method->getSourceRange();
-      Diag(Method->getLocation(),
-           diag::note_ovl_candidate_disabled_by_enable_if_attr)
-          << Attr->getCond()->getSourceRange() << Attr->getMessage();
-      return ExprError();
-    }
   } else {
     UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
     Qualifier = UnresExpr->getQualifier();
@@ -11837,6 +11827,21 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
   if (CheckFunctionCall(Method, TheCall, Proto))
     return ExprError();
 
+  // In the case the method to call was not selected by the overloading
+  // resolution process, we still need to handle the enable_if attribute. Do
+  // that here, so it will not hide previous -- and more relevant -- errors
+  if (isa<MemberExpr>(NakedMemExpr)) {
+    if (const EnableIfAttr *Attr = CheckEnableIf(Method, Args, true)) {
+      Diag(MemExprE->getLocStart(),
+           diag::err_ovl_no_viable_member_function_in_call)
+          << Method << Method->getSourceRange();
+      Diag(Method->getLocation(),
+           diag::note_ovl_candidate_disabled_by_enable_if_attr)
+          << Attr->getCond()->getSourceRange() << Attr->getMessage();
+      return ExprError();
+    }
+  }
+
   if ((isa<CXXConstructorDecl>(CurContext) || 
        isa<CXXDestructorDecl>(CurContext)) && 
       TheCall->getMethodDecl()->isPure()) {
index 27de4fed1f5ff071940315102539b80504a97c61..58460692b799f7871a1014a6e72ba6e51745f2eb 100644 (file)
@@ -2,6 +2,8 @@
 
 typedef int (*fp)(int);
 int surrogate(int);
+struct Incomplete;  // expected-note{{forward declaration of 'Incomplete'}} \
+                    // expected-note {{forward declaration of 'Incomplete'}}
 
 struct X {
   X() = default;  // expected-note{{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
@@ -13,13 +15,16 @@ struct X {
 
   void g(int n) __attribute__((enable_if(n == 0, "chosen when 'n' is zero")));  // expected-note{{candidate disabled: chosen when 'n' is zero}}
 
-  void h(int n, int m = 0) __attribute((enable_if(m == 0, "chosen when 'm' is zero")));  // expected-note{{candidate disabled: chosen when 'm' is zero}}
+  void h(int n, int m = 0) __attribute__((enable_if(m == 0, "chosen when 'm' is zero")));  // expected-note{{candidate disabled: chosen when 'm' is zero}}
 
   static void s(int n) __attribute__((enable_if(n == 0, "chosen when 'n' is zero")));  // expected-note2{{candidate disabled: chosen when 'n' is zero}}
 
   void conflict(int n) __attribute__((enable_if(n+n == 10, "chosen when 'n' is five")));  // expected-note{{candidate function}}
   void conflict(int n) __attribute__((enable_if(n*2 == 10, "chosen when 'n' is five")));  // expected-note{{candidate function}}
 
+  void hidden_by_argument_conversion(Incomplete n, int m = 0) __attribute__((enable_if(m == 10, "chosen when 'm' is ten")));
+  Incomplete hidden_by_incomplete_return_value(int n = 0) __attribute__((enable_if(n == 10, "chosen when 'n' is ten"))); // expected-note{{'hidden_by_incomplete_return_value' declared here}}
+
   operator long() __attribute__((enable_if(true, "chosen on your platform")));
   operator int() __attribute__((enable_if(false, "chosen on other platform")));
 
@@ -85,6 +90,9 @@ void test() {
 
   x.conflict(5);  // expected-error{{call to member function 'conflict' is ambiguous}}
 
+  x.hidden_by_argument_conversion(10);  // expected-error{{argument type 'Incomplete' is incomplete}}
+  x.hidden_by_incomplete_return_value(10);  // expected-error{{calling 'hidden_by_incomplete_return_value' with incomplete return type 'Incomplete'}}
+
   deprec2(0);
 
   overloaded(x);