|
17 | 17 | #include "clang/Analysis/AnalysisDeclContext.h" |
18 | 18 | #include "clang/Analysis/CFG.h" |
19 | 19 | #include "clang/Basic/Builtins.h" |
| 20 | +#include "clang/Basic/PartialDiagnostic.h" |
20 | 21 | #include "clang/Basic/SourceLocation.h" |
21 | 22 | #include "clang/Sema/Lookup.h" |
| 23 | +#include "clang/Sema/Sema.h" |
| 24 | +#include "clang/Sema/TemplateDeduction.h" |
22 | 25 |
|
23 | 26 | #include "llvm/ADT/SmallVector.h" |
24 | 27 | #include "llvm/Support/Casting.h" |
@@ -947,6 +950,80 @@ namespace clad { |
947 | 950 | return cast<TemplateDecl>(TapeR.getFoundDecl()); |
948 | 951 | } |
949 | 952 |
|
| 953 | + Expr* MatchOverloadType(Sema& S, QualType FnTy, LookupResult& Overloads, |
| 954 | + TemplateSpecCandidateSet& FailedCandidates) { |
| 955 | + CXXScopeSpec SS; |
| 956 | + ASTContext& C = S.getASTContext(); |
| 957 | + // Check if any of the custom derivative signature satisfy the |
| 958 | + // requirements. |
| 959 | + for (LookupResult::iterator I = Overloads.begin(), E = Overloads.end(); |
| 960 | + I != E; ++I) { |
| 961 | + NamedDecl* candidate = I.getDecl(); |
| 962 | + // Shadow decls don't provide enough information, go to the actual decl. |
| 963 | + if (auto* usingShadow = dyn_cast<UsingShadowDecl>(candidate)) |
| 964 | + candidate = usingShadow->getTargetDecl(); |
| 965 | + |
| 966 | + // Overload is a template, try to match the signature. |
| 967 | + if (auto* FTD = dyn_cast<FunctionTemplateDecl>(candidate)) { |
| 968 | + FunctionDecl* Specialization = nullptr; |
| 969 | + sema::TemplateDeductionInfo Info(FailedCandidates.getLocation()); |
| 970 | + TemplateArgumentListInfo ExplicitTemplateArgs; |
| 971 | + auto TDK = S.DeduceTemplateArguments(FTD, &ExplicitTemplateArgs, FnTy, |
| 972 | + Specialization, Info); |
| 973 | + |
| 974 | + // Instantiation with the required signature succeeded. |
| 975 | + if (TDK == clad_compat::CLAD_COMPAT_TemplateSuccess) |
| 976 | + return S.BuildDeclarationNameExpr(SS, Overloads, /*ADL=*/false) |
| 977 | + .get(); |
| 978 | + |
| 979 | + FailedCandidates.addCandidate().set( |
| 980 | + I.getPair(), FTD->getTemplatedDecl(), |
| 981 | + MakeDeductionFailureInfo(C, TDK, Info)); |
| 982 | + |
| 983 | + // Instantiation of parameters suceeded but clang doesn't consider |
| 984 | + // deduction successful because of the auto return type. |
| 985 | + if (Specialization && !Specialization->isTemplated() && |
| 986 | + Specialization->getReturnType()->isUndeducedAutoType()) |
| 987 | + return S.BuildDeclarationNameExpr(SS, Overloads, /*ADL=*/false) |
| 988 | + .get(); |
| 989 | + } |
| 990 | + auto* FD = dyn_cast<FunctionDecl>(candidate); |
| 991 | + if (!FD) |
| 992 | + continue; |
| 993 | + // Overload is just a FunctionDecl, check if the signature matches. |
| 994 | + if (C.hasSameFunctionTypeIgnoringExceptionSpec(FD->getType(), FnTy)) |
| 995 | + return S.BuildDeclarationNameExpr(SS, Overloads, /*ADL=*/false).get(); |
| 996 | + } |
| 997 | + return nullptr; |
| 998 | + } |
| 999 | + |
| 1000 | + void DiagnoseSignatureMismatch(Sema& S, QualType FnTy, |
| 1001 | + const LookupResult& Overloads) { |
| 1002 | + ASTContext& C = S.getASTContext(); |
| 1003 | + std::string Name = Overloads.getLookupName().getAsString(); |
| 1004 | + unsigned noteId = S.Diags.getCustomDiagID( |
| 1005 | + DiagnosticsEngine::Note, |
| 1006 | + "candidate '%0'" |
| 1007 | + "%select{| has different class%diff{ (expected $ but has $)|}1,2" |
| 1008 | + "| has different number of parameters (expected %2 but has %3)" |
| 1009 | + "| has type mismatch at %ordinal2 parameter" |
| 1010 | + "%diff{ (expected $ but has $)|}3,4" |
| 1011 | + "| has different return type%diff{ ($ expected but has $)|}2,3" |
| 1012 | + "| has different qualifiers (expected %2 but found %3)" |
| 1013 | + "| has different exception specification}1"); |
| 1014 | + |
| 1015 | + for (const NamedDecl* ND : Overloads) { |
| 1016 | + if (const auto* usingShadow = dyn_cast<UsingShadowDecl>(ND)) |
| 1017 | + ND = usingShadow->getTargetDecl(); |
| 1018 | + if (!isa<FunctionDecl>(ND)) |
| 1019 | + continue; |
| 1020 | + const auto* FD = cast<FunctionDecl>(ND); |
| 1021 | + auto PD = PartialDiagnostic(noteId, C.getDiagAllocator()) << Name; |
| 1022 | + S.HandleFunctionTypeMismatch(PD, FD->getType(), FnTy); |
| 1023 | + S.Diag(FD->getLocation(), PD); |
| 1024 | + } |
| 1025 | + } |
| 1026 | + |
950 | 1027 | bool isMemoryType(QualType T) { |
951 | 1028 | T = T.getCanonicalType(); |
952 | 1029 | if (T->isReferenceType()) |
|
0 commit comments