aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Type.h3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--lib/AST/Type.cpp20
-rw-r--r--lib/Sema/SemaDecl.cpp51
-rw-r--r--test/SemaCXX/nested-name-spec.cpp4
-rw-r--r--test/SemaCXX/out-of-line-def-mismatch.cpp24
6 files changed, 95 insertions, 10 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 2b72610226..d0d69651e2 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -503,6 +503,9 @@ public:
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;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7a79c5b27c..236368ce3a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2971,6 +2971,9 @@ def warn_member_extra_qualification : Warning<
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<
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index b32908bc8f..81627f2bf9 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -42,6 +42,26 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(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;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2b6cf312a1..542614ed9e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2884,22 +2884,47 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
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 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
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);
+ }
}
}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index ee6ca88573..8e73c3e2ed 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -29,7 +29,7 @@ static int A::C::cx2 = 17; // expected-error{{'static' can}}
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 @@ Operators::operator bool() {
}
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'}}
diff --git a/test/SemaCXX/out-of-line-def-mismatch.cpp b/test/SemaCXX/out-of-line-def-mismatch.cpp
new file mode 100644
index 0000000000..6ade5b802b
--- /dev/null
+++ b/test/SemaCXX/out-of-line-def-mismatch.cpp
@@ -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'}}