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.
llvm-svn: 136891
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2b6cf31..542614e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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);
+ }
}
}