[cfe-commits] r136891 - in /cfe/trunk: include/clang/AST/Type.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Type.cpp lib/Sema/SemaDecl.cpp test/SemaCXX/nested-name-spec.cpp test/SemaCXX/out-of-line-def-mismatch.cpp

Kaelyn Uhrain rikka at google.com
Thu Aug 4 10:40:00 PDT 2011


Author: rikka
Date: Thu Aug  4 12:40:00 2011
New Revision: 136891

URL: http://llvm.org/viewvc/llvm-project?rev=136891&view=rev
Log:
Match type names and give more info for out-of-line function definition errors.

Having a function declaration and definition with different types for a
parameter where the types have same (textual) name can occur when an unqualified
type name resolves to types in different namespaces in each location.

The error messages have been extended by adding notes that point to the first
parameter of the function definition that doesn't match the declaration, instead
of a generic "member declaration nearly matches". The generic message is still
used in cases where the mismatch is not in the paramenter list, such as
mismatched cv qualifiers on the member function itself.

Added:
    cfe/trunk/test/SemaCXX/out-of-line-def-mismatch.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaCXX/nested-name-spec.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=136891&r1=136890&r2=136891&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Aug  4 12:40:00 2011
@@ -503,6 +503,9 @@
   
   const Type *getTypePtrOrNull() const;
 
+  /// Retrieves a pointer to the name of the base type.
+  const IdentifierInfo *getBaseTypeIdentifier() const;
+
   /// Divides a QualType into its unqualified type and a set of local
   /// qualifiers.
   SplitQualType split() const;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=136891&r1=136890&r2=136891&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug  4 12:40:00 2011
@@ -2971,6 +2971,9 @@
 def err_member_qualification : Error<
   "non-friend class member %0 cannot have a qualified name">;  
 def note_member_def_close_match : Note<"member declaration nearly matches">;
+def note_member_def_close_param_match : Note<
+  "type of %ordinal0 parameter of member declaration does not match "
+  "definition (%1 vs %2)">;
 def err_typecheck_ivar_variable_size : Error<
   "instance variables must have a constant size">;
 def err_ivar_reference_type : Error<

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=136891&r1=136890&r2=136891&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Thu Aug  4 12:40:00 2011
@@ -42,6 +42,26 @@
      (hasObjCLifetime() && !Other.hasObjCLifetime()));
 }
 
+const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
+  const Type* ty = getTypePtr();
+  NamedDecl *ND = NULL;
+  if (ty->isPointerType() || ty->isReferenceType())
+    return ty->getPointeeType().getBaseTypeIdentifier();
+  else if (ty->isRecordType())
+    ND = ty->getAs<RecordType>()->getDecl();
+  else if (ty->isEnumeralType())
+    ND = ty->getAs<EnumType>()->getDecl();
+  else if (ty->getTypeClass() == Type::Typedef)
+    ND = ty->getAs<TypedefType>()->getDecl();
+  else if (ty->isArrayType())
+    return ty->castAsArrayTypeUnsafe()->
+        getElementType().getBaseTypeIdentifier();
+
+  if (ND)
+    return ND->getIdentifier();
+  return NULL;
+}
+
 bool QualType::isConstant(QualType T, ASTContext &Ctx) {
   if (T.isConstQualified())
     return true;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=136891&r1=136890&r2=136891&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug  4 12:40:00 2011
@@ -2884,22 +2884,47 @@
   return DeclarationNameInfo();
 }
 
+static QualType getCoreType(QualType Ty) {
+  do {
+    if (Ty->isPointerType() || Ty->isReferenceType())
+      Ty = Ty->getPointeeType();
+    else if (Ty->isArrayType())
+      Ty = Ty->castAsArrayTypeUnsafe()->getElementType();
+    else
+      return Ty.withoutLocalFastQualifiers();
+  } while (true);
+}
+
 /// isNearlyMatchingFunction - Determine whether the C++ functions
 /// Declaration and Definition are "nearly" matching. This heuristic
 /// is used to improve diagnostics in the case where an out-of-line
-/// function definition doesn't match any declaration within
-/// the class or namespace.
+/// function definition doesn't match any declaration within the class
+/// or namespace. Also sets Params to the list of indices to the
+/// parameters that differ between the declaration and the definition.
 static bool isNearlyMatchingFunction(ASTContext &Context,
                                      FunctionDecl *Declaration,
-                                     FunctionDecl *Definition) {
+                                     FunctionDecl *Definition,
+                                     llvm::SmallVectorImpl<unsigned> &Params) {
+  Params.clear();
   if (Declaration->param_size() != Definition->param_size())
     return false;
   for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) {
     QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType();
     QualType DefParamTy = Definition->getParamDecl(Idx)->getType();
 
-    if (!Context.hasSameUnqualifiedType(DeclParamTy.getNonReferenceType(),
-                                        DefParamTy.getNonReferenceType()))
+    // The parameter types are identical
+    if (DefParamTy == DeclParamTy)
+      continue;
+
+    QualType DeclParamBaseTy = getCoreType(DeclParamTy);
+    QualType DefParamBaseTy = getCoreType(DefParamTy);
+    const IdentifierInfo *DeclTyName = DeclParamBaseTy.getBaseTypeIdentifier();
+    const IdentifierInfo *DefTyName = DefParamBaseTy.getBaseTypeIdentifier();
+
+    if (Context.hasSameUnqualifiedType(DeclParamBaseTy, DefParamBaseTy) ||
+        (DeclTyName && DeclTyName == DefTyName))
+      Params.push_back(Idx);
+    else  // The two parameters aren't even close
       return false;
   }
 
@@ -4155,14 +4180,24 @@
 static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {
   LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(),
                     Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+  llvm::SmallVector<unsigned, 1> MismatchedParams;
   S.LookupQualifiedName(Prev, NewFD->getDeclContext());
   assert(!Prev.isAmbiguous() &&
          "Cannot have an ambiguity in previous-declaration lookup");
   for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
        Func != FuncEnd; ++Func) {
-    if (isa<FunctionDecl>(*Func) &&
-        isNearlyMatchingFunction(S.Context, cast<FunctionDecl>(*Func), NewFD))
-      S.Diag((*Func)->getLocation(), diag::note_member_def_close_match);
+    FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);
+    if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,
+                                       MismatchedParams)) {
+      if (MismatchedParams.size() > 0) {
+        unsigned Idx = MismatchedParams.front();
+        ParmVarDecl *FDParam = FD->getParamDecl(Idx);
+        S.Diag(FDParam->getTypeSpecStartLoc(),
+               diag::note_member_def_close_param_match)
+            << Idx+1 << FDParam->getType() << NewFD->getParamDecl(Idx)->getType();
+      } else
+        S.Diag(FD->getLocation(), diag::note_member_def_close_match);
+    }
   }
 }
 

Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=136891&r1=136890&r2=136891&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Thu Aug  4 12:40:00 2011
@@ -29,7 +29,7 @@
 class C2 {
   void m(); // expected-note{{member declaration nearly matches}}
 
-  void f(const int& parm); // expected-note{{member declaration nearly matches}}
+  void f(const int& parm); // expected-note{{type of 1st parameter of member declaration does not match definition ('const int &' vs 'int')}}
   void f(int) const; // expected-note{{member declaration nearly matches}}
   void f(float);
 
@@ -140,7 +140,7 @@
 }
 
 namespace A {
-  void g(int&); // expected-note{{member declaration nearly matches}}
+  void g(int&); // expected-note{{type of 1st parameter of member declaration does not match definition ('int &' vs 'const int &')}}
 } 
 
 void A::f() {} // expected-error{{out-of-line definition of 'f' does not match any declaration in namespace 'A'}}

Added: cfe/trunk/test/SemaCXX/out-of-line-def-mismatch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/out-of-line-def-mismatch.cpp?rev=136891&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/out-of-line-def-mismatch.cpp (added)
+++ cfe/trunk/test/SemaCXX/out-of-line-def-mismatch.cpp Thu Aug  4 12:40:00 2011
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s
+
+namespace N2 {
+  struct S1;
+
+  namespace N1 {
+    class C1 {};
+
+    struct S2 {
+      void func(S1*); // expected-note {{type of 1st parameter of member declaration does not match definition ('N2::S1 *' vs 'N2::N1::S1 *')}}
+      void func(C1&, unsigned, const S1*); // expected-note {{type of 3rd parameter of member declaration does not match definition ('const N2::S1 *' vs 'const N2::N1::S1 *')}}
+      void func(const S1*, unsigned); //expected-note {{type of 1st parameter of member declaration does not match definition ('const N2::S1 *' vs 'N2::N1::S1')}}
+      void func(unsigned, const S1*); // expected-note {{type of 1st parameter of member declaration does not match definition ('unsigned int' vs 'unsigned int *')}}
+    };
+
+    struct S1 {};
+  }
+}
+
+void N2::N1::S2::func(S1*) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(C1&, unsigned, const S1*) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(S1*, double) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(S1, unsigned) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(unsigned*, S1*) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}





More information about the cfe-commits mailing list