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/Sema/SemaTemplate.cpp | |
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/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 48 |
1 files changed, 47 insertions, 1 deletions
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 |