[cfe-commits] r91525 - in /cfe/trunk: include/clang/Basic/ lib/Sema/ test/CXX/basic/basic.lookup/basic.lookup.argdep/ test/CXX/temp/temp.fct.spec/temp.arg.explicit/ test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/ test/SemaCXX/ test/SemaTemplate/

John McCall rjmccall at apple.com
Wed Dec 16 00:11:27 PST 2009


Author: rjmccall
Date: Wed Dec 16 02:11:27 2009
New Revision: 91525

URL: http://llvm.org/viewvc/llvm-project?rev=91525&view=rev
Log:
Introduce a centralized routine in Sema for diagnosing failed lookups (when
used as expressions).  In dependent contexts, try to recover by doing a lookup
in previously-dependent base classes.  We get better diagnostics out, but    
unfortunately the recovery fails:  we need to turn it into a method call  
expression, not a bare call expression.  Thus this is still a WIP.



Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
    cfe/trunk/test/SemaCXX/conversion-function.cpp
    cfe/trunk/test/SemaCXX/decltype-crash.cpp
    cfe/trunk/test/SemaCXX/no-implicit-builtin-decls.cpp
    cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
    cfe/trunk/test/SemaTemplate/constructor-template.cpp
    cfe/trunk/test/SemaTemplate/dependent-names.cpp
    cfe/trunk/test/SemaTemplate/instantiate-call.cpp
    cfe/trunk/test/SemaTemplate/recursive-template-instantiation.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Dec 16 02:11:27 2009
@@ -1279,7 +1279,9 @@
 def err_unexpected_namespace : Error<
   "unexpected namespace name %0: expected expression">;
 def err_undeclared_var_use : Error<"use of undeclared identifier %0">;
-def err_undeclared_use : Error<"use of undeclared '%0'">;
+def note_dependent_var_use : Note<"must qualify identifier to find this "
+    "declaration in dependent base class">;
+def err_undeclared_use : Error<"use of undeclared %0">;
 def warn_deprecated : Warning<"%0 is deprecated">,
     InGroup<DiagGroup<"deprecated-declarations">>;
 def warn_unavailable : Warning<"%0 is unavailable">,

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Dec 16 02:11:27 2009
@@ -1479,6 +1479,8 @@
                                              bool HasTrailingLParen,
                                              bool IsAddressOfOperand);
 
+  bool DiagnoseEmptyLookup(const CXXScopeSpec &SS, LookupResult &R);
+
   OwningExprResult LookupInObjCMethod(LookupResult &R,
                                       Scope *S,
                                       IdentifierInfo *II);

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Dec 16 02:11:27 2009
@@ -917,6 +917,68 @@
   SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
 }
 
+/// Diagnose an empty lookup.
+///
+/// \return false if new lookup candidates were found
+bool Sema::DiagnoseEmptyLookup(const CXXScopeSpec &SS,
+                               LookupResult &R) {
+  DeclarationName Name = R.getLookupName();
+
+  // We don't know how to recover from bad qualified lookups.
+  if (!SS.isEmpty()) {
+    Diag(R.getNameLoc(), diag::err_no_member)
+      << Name << computeDeclContext(SS, false)
+      << SS.getRange();
+    return true;
+  }
+
+  unsigned diagnostic = diag::err_undeclared_var_use;
+  if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
+      Name.getNameKind() == DeclarationName::CXXLiteralOperatorName ||
+      Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
+    diagnostic = diag::err_undeclared_use;
+
+  // Fake an unqualified lookup.  This is useful when (for example)
+  // the original lookup would not have found something because it was
+  // a dependent name.
+  for (DeclContext *DC = CurContext; DC; DC = DC->getParent()) {
+    if (isa<CXXRecordDecl>(DC)) {
+      LookupQualifiedName(R, DC);
+
+      if (!R.empty()) {
+        // Don't give errors about ambiguities in this lookup.
+        R.suppressDiagnostics();
+
+        CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
+        bool isInstance = CurMethod &&
+                          CurMethod->isInstance() &&
+                          DC == CurMethod->getParent();
+
+        // Give a code modification hint to insert 'this->'.
+        // TODO: fixit for inserting 'Base<T>::' in the other cases.
+        // Actually quite difficult!
+        if (isInstance)
+          Diag(R.getNameLoc(), diagnostic) << Name
+            << CodeModificationHint::CreateInsertion(R.getNameLoc(),
+                                                     "this->");
+        else
+          Diag(R.getNameLoc(), diagnostic) << Name;
+
+        // Do we really want to note all of these?
+        for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+          Diag((*I)->getLocation(), diag::note_dependent_var_use);
+
+        // Tell the callee to try to recover.
+        return false;
+      }
+    }
+  }
+
+  // Give up, we can't recover.
+  Diag(R.getNameLoc(), diagnostic) << Name;
+  return true;
+}
+
 Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
                                                const CXXScopeSpec &SS,
                                                UnqualifiedId &Id,
@@ -989,17 +1051,11 @@
     // If this name wasn't predeclared and if this is not a function
     // call, diagnose the problem.
     if (R.empty()) {
-      if (!SS.isEmpty())
-        return ExprError(Diag(NameLoc, diag::err_no_member)
-                           << Name << computeDeclContext(SS, false)
-                           << SS.getRange());
-      else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
-               Name.getNameKind() == DeclarationName::CXXLiteralOperatorName ||
-               Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
-        return ExprError(Diag(NameLoc, diag::err_undeclared_use)
-                           << Name);
-      else
-        return ExprError(Diag(NameLoc, diag::err_undeclared_var_use) << Name);
+      if (DiagnoseEmptyLookup(SS, R))
+        return ExprError();
+
+      assert(!R.empty() &&
+             "DiagnoseEmptyLookup returned false but added no results");
     }
   }
 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Dec 16 02:11:27 2009
@@ -2622,7 +2622,14 @@
                                   Args, NumArgs, Specialization, Info)) {
     // FIXME: Record what happened with template argument deduction, so
     // that we can give the user a beautiful diagnostic.
-    (void)Result;
+    (void) Result;
+
+    CandidateSet.push_back(OverloadCandidate());
+    OverloadCandidate &Candidate = CandidateSet.back();
+    Candidate.Function = FunctionTemplate->getTemplatedDecl();
+    Candidate.Viable = false;
+    Candidate.IsSurrogate = false;
+    Candidate.IgnoreObjectArgument = false;
     return;
   }
 
@@ -4637,6 +4644,34 @@
                                          CandidateSet,
                                          PartialOverloading);  
 }
+
+/// Attempts to recover from a call where no functions were found.
+///
+/// Returns true if new candidates were found.
+static bool AddRecoveryCallCandidates(Sema &SemaRef, Expr *Fn,
+                         const TemplateArgumentListInfo *ExplicitTemplateArgs,
+                                      Expr **Args, unsigned NumArgs,
+                                      OverloadCandidateSet &CandidateSet) {
+  UnresolvedLookupExpr *ULE
+    = cast<UnresolvedLookupExpr>(Fn->IgnoreParenCasts());
+
+  CXXScopeSpec SS;
+  if (ULE->getQualifier()) {
+    SS.setScopeRep(ULE->getQualifier());
+    SS.setRange(ULE->getQualifierRange());
+  }
+
+  LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
+                 Sema::LookupOrdinaryName);
+  if (SemaRef.DiagnoseEmptyLookup(SS, R))
+    return false;
+
+  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+    AddOverloadedCallCandidate(SemaRef, *I, ExplicitTemplateArgs,
+                               Args, NumArgs, CandidateSet, false);
+  }
+  return true;
+}
   
 /// ResolveOverloadedCallFn - Given the call expression that calls Fn
 /// (which eventually refers to the declaration Func) and the call
@@ -4661,6 +4696,19 @@
   AddOverloadedCallCandidates(Fns, UnqualifiedName, ArgumentDependentLookup,
                               ExplicitTemplateArgs, Args, NumArgs, 
                               CandidateSet);
+
+  // If we found nothing, try to recover.
+  // AddRecoveryCallCandidates diagnoses the error itself, so we just
+  // bailout out if it fails.
+  if (CandidateSet.empty() &&
+      !AddRecoveryCallCandidates(*this, Fn, ExplicitTemplateArgs,
+                                 Args, NumArgs, CandidateSet)) {
+    Fn->Destroy(Context);
+    for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+      Args[Arg]->Destroy(Context);
+    return 0;
+  }
+
   OverloadCandidateSet::iterator Best;
   switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
   case OR_Success:

Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp Wed Dec 16 02:11:27 2009
@@ -32,7 +32,7 @@
 namespace Test {
   void test() {
     func(A::A());
-    func(B::B()); // expected-error {{ no matching function for call to 'func' }}
+    func(B::B()); // expected-error {{use of undeclared identifier 'func'}}
     func(C::C());
     A::A() + A::A();
     B::B() + B::B();

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp Wed Dec 16 02:11:27 2009
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-template<class X, class Y, class Z> X f(Y,Z); 
+template<class X, class Y, class Z> X f(Y,Z); // expected-note {{candidate function}}
 
 void g() {
   f<int,char*,double>("aa",3.0); 

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp Wed Dec 16 02:11:27 2009
@@ -15,7 +15,7 @@
   f1(ip, fv);
 }
 
-template<typename T> void f2(T*, T*);
+template<typename T> void f2(T*, T*); // expected-note 2 {{candidate function}}
 
 struct ConvToIntPtr {
   operator int*() const;

Modified: cfe/trunk/test/SemaCXX/conversion-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conversion-function.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/conversion-function.cpp (original)
+++ cfe/trunk/test/SemaCXX/conversion-function.cpp Wed Dec 16 02:11:27 2009
@@ -9,7 +9,7 @@
   }
 
   float g() {
-    return operator float(); // expected-error{{no matching function for call to 'operator float'}}
+    return operator float(); // expected-error{{use of undeclared 'operator float'}}
   }
 };
 

Modified: cfe/trunk/test/SemaCXX/decltype-crash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decltype-crash.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/decltype-crash.cpp (original)
+++ cfe/trunk/test/SemaCXX/decltype-crash.cpp Wed Dec 16 02:11:27 2009
@@ -3,5 +3,5 @@
 int& a();
 
 void f() {
-  decltype(a()) c; // expected-error {{no matching function for call to 'decltype'}}
+  decltype(a()) c; // expected-error {{use of undeclared identifier 'decltype'}}
 }

Modified: cfe/trunk/test/SemaCXX/no-implicit-builtin-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/no-implicit-builtin-decls.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/no-implicit-builtin-decls.cpp (original)
+++ cfe/trunk/test/SemaCXX/no-implicit-builtin-decls.cpp Wed Dec 16 02:11:27 2009
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 void f() {
-  void *p = malloc(sizeof(int) * 10); // expected-error{{no matching function for call to 'malloc'}}
+  void *p = malloc(sizeof(int) * 10); // expected-error{{use of undeclared identifier 'malloc'}}
 }
 
 int malloc(double);

Modified: cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp Wed Dec 16 02:11:27 2009
@@ -19,6 +19,6 @@
   return g(x);
   h(x); // h is a dependent name
   g(1, 1); // expected-error{{no matching function for call}}
-  h(1); // expected-error{{no matching function for call to 'h'}}
+  h(1); // expected-error{{use of undeclared identifier 'h'}}
   return 0;
 }

Modified: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Wed Dec 16 02:11:27 2009
@@ -1,11 +1,11 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 struct X0 { // expected-note{{candidate}}
   X0(int); // expected-note{{candidate}}
-  template<typename T> X0(T);
-  template<typename T, typename U> X0(T*, U*);
+  template<typename T> X0(T); // expected-note {{candidate}}
+  template<typename T, typename U> X0(T*, U*); // expected-note {{candidate}}
   
   // PR4761
-  template<typename T> X0() : f0(T::foo) {}
+  template<typename T> X0() : f0(T::foo) {} // expected-note {{candidate}}
   int f0;
 };
 

Modified: cfe/trunk/test/SemaTemplate/dependent-names.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-names.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/dependent-names.cpp (original)
+++ cfe/trunk/test/SemaTemplate/dependent-names.cpp Wed Dec 16 02:11:27 2009
@@ -84,3 +84,18 @@
     d2.test3(); // expected-note {{in instantiation of member function}}
   }
 }
+
+namespace test1 {
+  template <class T> struct Base {
+    void foo(T); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+  };
+
+  template <class T> struct Derived : Base<T> {
+    void doFoo(T v) {
+      // FIXME: the second error here is from a broken recovery attempt
+      foo(v); // expected-error {{use of undeclared identifier}} expected-error {{call to non-static member function without an object}}
+    }
+  };
+
+  template struct Derived<int>; // expected-note {{requested here}}
+}

Modified: cfe/trunk/test/SemaTemplate/instantiate-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-call.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-call.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-call.cpp Wed Dec 16 02:11:27 2009
@@ -24,7 +24,7 @@
   template<typename T, typename Result>
   struct call_f0 {
     void test_f0(T t) {
-      Result &result = f0(t); // expected-error 2{{no matching}}
+      Result &result = f0(t); // expected-error 2{{undeclared identifier}}
     }
   };
 }

Modified: cfe/trunk/test/SemaTemplate/recursive-template-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/recursive-template-instantiation.cpp?rev=91525&r1=91524&r2=91525&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/recursive-template-instantiation.cpp (original)
+++ cfe/trunk/test/SemaTemplate/recursive-template-instantiation.cpp Wed Dec 16 02:11:27 2009
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-template<typename T> void f(T* t) {
+template<typename T> void f(T* t) { // expected-note{{candidate function}}
   f(*t); // expected-error{{no matching function}}\
          // expected-note 3{{requested here}}
 }





More information about the cfe-commits mailing list