diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-05-09 05:17:00 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-05-09 05:17:00 +0000 |
commit | 4493c0aa8add05b2fc534b0d8970c4b5480fad3b (patch) | |
tree | 460cb8211a76b4b7a30527d2c53c126d9274fbf4 /lib | |
parent | 2d99c59aced6d6cd599209cb999a7da773702a42 (diff) |
A little tweak to the SFINAE condition reporting. Don't say:
candidate template ignored: substitution failed [with T = int]: no type named 'type' in 'std::enable_if<false, void>'
Instead, just say:
candidate template ignored: disabled by 'enable_if' [with T = int]
... and point at the enable_if condition which (we assume) failed.
This is applied to all cases where the user writes 'typename enable_if<...>::type' (optionally prefixed with a nested name specifier), and 'enable_if<...>' names a complete class type which does not have a member named 'type', and this results in a candidate function being ignored in a SFINAE context. Thus it catches 'std::enable_if', 'std::__1::enable_if', 'boost::enable_if' and 'llvm::enable_if'.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156463 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 48 |
2 files changed, 59 insertions, 3 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f065d38d92..b99a638bda 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -8263,13 +8263,23 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, Fn->getDescribedFunctionTemplate()->getTemplateParameters(), *Args); } + // If this candidate was disabled by enable_if, say so. + PartialDiagnosticAt *PDiag = Cand->DeductionFailure.getSFINAEDiagnostic(); + if (PDiag && PDiag->second.getDiagID() == + diag::err_typename_nested_not_found_enable_if) { + // FIXME: Use the source range of the condition, and the fully-qualified + // name of the enable_if template. These are both present in PDiag. + S.Diag(PDiag->first, diag::note_ovl_candidate_disabled_by_enable_if) + << "'enable_if'" << TemplateArgString; + return; + } + // Format the SFINAE diagnostic into the argument string. // FIXME: Add a general mechanism to include a PartialDiagnostic *'s // formatted message in another diagnostic. llvm::SmallString<128> SFINAEArgString; SourceRange R; - if (PartialDiagnosticAt *PDiag = - Cand->DeductionFailure.getSFINAEDiagnostic()) { + if (PDiag) { SFINAEArgString = ": "; R = SourceRange(PDiag->first, PDiag->first); PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index bde80fd5b1..7faf80edfc 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6923,6 +6923,42 @@ Sema::ActOnTypenameType(Scope *S, } +/// Determine whether this failed name lookup should be treated as being +/// disabled by a usage of std::enable_if. +static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, + SourceRange &CondRange) { + // We must be looking for a ::type... + if (!II.isStr("type")) + return false; + + // ... within an explicitly-written template specialization... + if (!NNS || !NNS.getNestedNameSpecifier()->getAsType()) + return false; + TypeLoc EnableIfTy = NNS.getTypeLoc(); + TemplateSpecializationTypeLoc *EnableIfTSTLoc = + dyn_cast<TemplateSpecializationTypeLoc>(&EnableIfTy); + if (!EnableIfTSTLoc || EnableIfTSTLoc->getNumArgs() == 0) + return false; + const TemplateSpecializationType *EnableIfTST = + cast<TemplateSpecializationType>(EnableIfTSTLoc->getTypePtr()); + + // ... which names a complete class template declaration... + const TemplateDecl *EnableIfDecl = + EnableIfTST->getTemplateName().getAsTemplateDecl(); + if (!EnableIfDecl || EnableIfTST->isIncompleteType()) + return false; + + // ... called "enable_if". + const IdentifierInfo *EnableIfII = + EnableIfDecl->getDeclName().getAsIdentifierInfo(); + if (!EnableIfII || !EnableIfII->isStr("enable_if")) + return false; + + // Assume the first template argument is the condition. + CondRange = EnableIfTSTLoc->getArgLoc(0).getSourceRange(); + return true; +} + /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType @@ -6959,9 +6995,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, unsigned DiagID = 0; Decl *Referenced = 0; switch (Result.getResultKind()) { - case LookupResult::NotFound: + case LookupResult::NotFound: { + // If we're looking up 'type' within a template named 'enable_if', produce + // a more specific diagnostic. + SourceRange CondRange; + if (isEnableIf(QualifierLoc, II, CondRange)) { + Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) + << Ctx << CondRange; + return QualType(); + } + DiagID = diag::err_typename_nested_not_found; break; + } case LookupResult::FoundUnresolvedValue: { // We found a using declaration that is a value. Most likely, the using |