explicit functions that are not candidates.
It's not always obvious that the reason a conversion was not possible is
because the function you wanted to call is 'explicit', so explicitly say
if that's the case.
It would be nice to rank the explicit candidates higher in the
diagnostic if an implicit conversion sequence exists for their
arguments, but unfortunately we can't determine that without potentially
triggering non-immediate-context errors that we're not permitted to
produce.
};
/// Store information needed for an explicit specifier.
-/// used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl.
+/// Used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl.
class ExplicitSpecifier {
llvm::PointerIntPair<Expr *, 2, ExplicitSpecKind> ExplicitSpec{
nullptr, ExplicitSpecKind::ResolvedFalse};
const Expr *getExpr() const { return ExplicitSpec.getPointer(); }
Expr *getExpr() { return ExplicitSpec.getPointer(); }
- /// Return true if the ExplicitSpecifier isn't defaulted.
+ /// Determine if the declaration had an explicit specifier of any kind.
bool isSpecified() const {
return ExplicitSpec.getInt() != ExplicitSpecKind::ResolvedFalse ||
ExplicitSpec.getPointer();
}
- /// Check for Equivalence of explicit specifiers.
- /// Return True if the explicit specifier are equivalent false otherwise.
+ /// Check for equivalence of explicit specifiers.
+ /// \return true if the explicit specifier are equivalent, false otherwise.
bool isEquivalent(const ExplicitSpecifier Other) const;
- /// Return true if the explicit specifier is already resolved to be explicit.
+ /// Determine whether this specifier is known to correspond to an explicit
+ /// declaration. Returns false if the specifier is absent or has an
+ /// expression that is value-dependent or evaluates to false.
bool isExplicit() const {
return ExplicitSpec.getInt() == ExplicitSpecKind::ResolvedTrue;
}
- /// Return true if the ExplicitSpecifier isn't valid.
+ /// Determine if the explicit specifier is invalid.
/// This state occurs after a substitution failures.
bool isInvalid() const {
return ExplicitSpec.getInt() == ExplicitSpecKind::Unresolved &&
}
void setKind(ExplicitSpecKind Kind) { ExplicitSpec.setInt(Kind); }
void setExpr(Expr *E) { ExplicitSpec.setPointer(E); }
- // getFromDecl - retrieve the explicit specifier in the given declaration.
- // if the given declaration has no explicit. the returned explicit specifier
- // is defaulted. .isSpecified() will be false.
+ // Retrieve the explicit specifier in the given declaration, if any.
static ExplicitSpecifier getFromDecl(FunctionDecl *Function);
static const ExplicitSpecifier getFromDecl(const FunctionDecl *Function) {
return getFromDecl(const_cast<FunctionDecl *>(Function));
"| has different qualifiers (expected %5 but found %6)"
"| has different exception specification}4">;
-def note_ovl_candidate_explicit_forbidden : Note<
- "candidate %0 ignored: cannot be explicit">;
-def note_explicit_bool_resolved_to_true : Note<
- "explicit(bool) specifier resolved to true">;
+def note_ovl_candidate_explicit : Note<
+ "explicit %select{constructor|conversion function|deduction guide}0 "
+ "is not a candidate%select{| (explicit specifier evaluates to true)}1">;
def note_ovl_candidate_inherited_constructor : Note<
"constructor from base class %0 inherited here">;
def note_ovl_candidate_inherited_constructor_slice : Note<
/// attribute disabled it.
ovl_fail_enable_if,
- /// This candidate constructor or conversion fonction
- /// is used implicitly but the explicit(bool) specifier
- /// was resolved to true
- ovl_fail_explicit_resolved,
+ /// This candidate constructor or conversion function is explicit but
+ /// the context doesn't permit explicit functions.
+ ovl_fail_explicit,
/// This candidate was not viable because its address could not be taken.
ovl_fail_addr_not_available,
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
continue;
- if (!AllowExplicit && Info.Constructor->isExplicit())
- continue;
-
if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
continue;
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit, AllowExplicit,
- /*AllowResultConversion*/ false);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
- DestType, CandidateSet, AllowExplicit,
- AllowExplicit,
- /*AllowResultConversion*/ false);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit,
+ /*AllowResultConversion*/ false);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ AllowExplicit,
+ /*AllowResultConversion*/ false);
}
}
}
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
+ Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
// FIXME: Do we need to make sure that we only consider conversion
// candidates with reference-compatible results? That might be needed to
// break recursion.
- if ((AllowExplicitConvs || !Conv->isExplicit()) &&
- (AllowRValues ||
+ if ((AllowRValues ||
Conv->getConversionType()->isLValueReferenceType())) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+ Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit, AllowExplicit);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
- DestType, CandidateSet, AllowExplicit,
- AllowExplicit);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ AllowExplicit);
}
}
}
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
if (!AllowExplicit) {
- // Only consider converting constructors.
- if (GD->isExplicit())
- continue;
+ // Overload resolution checks whether the deduction guide is declared
+ // explicit for us.
// When looking for a converting constructor, deduction guides that
// could never be called with one argument are not interesting to
continue;
bool Usable = !Info.Constructor->isInvalidDecl() &&
- S.isInitListConstructor(Info.Constructor) &&
- (AllowExplicit || !Info.Constructor->isExplicit());
+ S.isInitListConstructor(Info.Constructor);
if (Usable) {
// If the first argument is (a reference to) the target type,
// suppress conversions.
continue;
bool Usable = !Info.Constructor->isInvalidDecl();
- if (ListInitializing)
- Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit());
- else
- Usable = Usable &&
- Info.Constructor->isConvertingConstructor(AllowExplicit);
+ if (!ListInitializing)
+ Usable = Usable && Info.Constructor->isConvertingConstructor(
+ /*AllowExplicit*/ true);
if (Usable) {
bool SuppressUserConversions = !ConstructorsOnly;
if (SuppressUserConversions && ListInitializing) {
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, FoundDecl, ActingContext, From, ToType,
- CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
- else
- S.AddConversionCandidate(
- Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
- AllowObjCConversionOnExplicit, AllowExplicit);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, FoundDecl, ActingContext, From, ToType,
+ CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
+ else
+ S.AddConversionCandidate(
+ Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
+ AllowObjCConversionOnExplicit, AllowExplicit);
}
}
}
else
Conv = cast<CXXConversionDecl>(D);
- // If this is an explicit conversion, and we're not allowed to consider
- // explicit conversions, skip it.
- if (!AllowExplicit && Conv->isExplicit())
- continue;
-
if (AllowRvalues) {
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
+ // Explicit functions are not actually candidates at all if we're not
+ // allowing them in this context, but keep them around so we can point
+ // to them in diagnostics.
+ if (!AllowExplicit && ExplicitSpecifier::getFromDecl(Function).isExplicit()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
!Function->getAttr<TargetAttr>()->isDefaultVersion()) {
Candidate.Viable = false;
}
}
- if (!AllowExplicit) {
- ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
- if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
- Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_explicit_resolved;
- return;
- }
- }
-
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Conversions, PO);
}
+/// Determine whether a given function template has a simple explicit specifier
+/// or a non-value-dependent explicit-specification that evaluates to true.
+static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
+ return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
+}
+
/// Add a C++ function template specialization as a candidate
/// in the candidate set, using template argument deduction to produce
/// an appropriate function template specialization.
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
return;
+ // If the function template has a non-dependent explicit specification,
+ // exclude it now if appropriate; we are not permitted to perform deduction
+ // and substitution in this case.
+ if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
// C++ [over.match.funcs]p7:
// In each case where a candidate is a function template, candidate
// function template specializations are generated using template argument
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
// operator is only a candidate if its return type is the target type or
// can be converted to the target type with a qualification conversion.
+ //
+ // FIXME: Include such functions in the candidate list and explain why we
+ // can't select them.
if (Conversion->isExplicit() &&
!isAllowableExplicitConversion(*this, ConvType, ToType,
AllowObjCConversionOnExplicit))
Candidate.Viable = true;
Candidate.ExplicitCallArguments = 1;
+ // Explicit functions are not actually candidates at all if we're not
+ // allowing them in this context, but keep them around so we can point
+ // to them in diagnostics.
+ if (!AllowExplicit && Conversion->isExplicit()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
// C++ [over.match.funcs]p4:
// For conversion functions, the function is considered to be a member of
// the class of the implicit implied object argument for the purpose of
"Can only end up with a standard conversion sequence or failure");
}
- if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() !=
- ExplicitSpecKind::ResolvedFalse) {
- Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_explicit_resolved;
- return;
- }
-
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
+ // If the function template has a non-dependent explicit specification,
+ // exclude it now if appropriate; we are not permitted to perform deduction
+ // and substitution in this case.
+ if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
TemplateDeductionInfo Info(CandidateSet.getLocation());
CXXConversionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result
}
static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
- ExplicitSpecifier ES;
- const char *DeclName;
+ ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function);
+ assert(ES.isExplicit() && "not an explicit candidate");
+
+ unsigned Kind;
switch (Cand->Function->getDeclKind()) {
case Decl::Kind::CXXConstructor:
- ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "constructor";
+ Kind = 0;
break;
case Decl::Kind::CXXConversion:
- ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "conversion operator";
+ Kind = 1;
break;
case Decl::Kind::CXXDeductionGuide:
- ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "deductiong guide";
+ Kind = Cand->Function->isImplicit() ? 0 : 2;
break;
default:
llvm_unreachable("invalid Decl");
}
- assert(ES.getExpr() && "null expression should be handled before");
- S.Diag(Cand->Function->getLocation(),
- diag::note_ovl_candidate_explicit_forbidden)
- << DeclName;
- S.Diag(ES.getExpr()->getBeginLoc(),
- diag::note_explicit_bool_resolved_to_true);
+
+ // Note the location of the first (in-class) declaration; a redeclaration
+ // (particularly an out-of-class definition) will typically lack the
+ // 'explicit' specifier.
+ // FIXME: This is probably a good thing to do for all 'candidate' notes.
+ FunctionDecl *First = Cand->Function->getFirstDecl();
+ if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern())
+ First = Pattern->getFirstDecl();
+
+ S.Diag(First->getLocation(),
+ diag::note_ovl_candidate_explicit)
+ << Kind << (ES.getExpr() ? 1 : 0)
+ << (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
- case ovl_fail_explicit_resolved:
+ case ovl_fail_explicit:
return DiagnoseFailedExplicitSpec(S, Cand);
case ovl_fail_ext_disabled:
OverloadCandidateSet::CandidateSetKind CSK)
: S(S), NumArgs(NArgs), CSK(CSK) {}
+ OverloadFailureKind EffectiveFailureKind(const OverloadCandidate *C) const {
+ // If there are too many or too few arguments, that's the high-order bit we
+ // want to sort by, even if the immediate failure kind was something else.
+ if (C->FailureKind == ovl_fail_too_many_arguments ||
+ C->FailureKind == ovl_fail_too_few_arguments)
+ return static_cast<OverloadFailureKind>(C->FailureKind);
+
+ if (C->Function) {
+ if (NumArgs > C->Function->getNumParams() && !C->Function->isVariadic())
+ return ovl_fail_too_many_arguments;
+ if (NumArgs < C->Function->getMinRequiredArguments())
+ return ovl_fail_too_few_arguments;
+ }
+
+ return static_cast<OverloadFailureKind>(C->FailureKind);
+ }
+
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
// Fast-path this check.
// Criteria by which we can sort non-viable candidates:
if (!L->Viable) {
+ OverloadFailureKind LFailureKind = EffectiveFailureKind(L);
+ OverloadFailureKind RFailureKind = EffectiveFailureKind(R);
+
// 1. Arity mismatches come after other candidates.
- if (L->FailureKind == ovl_fail_too_many_arguments ||
- L->FailureKind == ovl_fail_too_few_arguments) {
- if (R->FailureKind == ovl_fail_too_many_arguments ||
- R->FailureKind == ovl_fail_too_few_arguments) {
+ if (LFailureKind == ovl_fail_too_many_arguments ||
+ LFailureKind == ovl_fail_too_few_arguments) {
+ if (RFailureKind == ovl_fail_too_many_arguments ||
+ RFailureKind == ovl_fail_too_few_arguments) {
int LDist = std::abs((int)L->getNumParams() - (int)NumArgs);
int RDist = std::abs((int)R->getNumParams() - (int)NumArgs);
if (LDist == RDist) {
- if (L->FailureKind == R->FailureKind)
+ if (LFailureKind == RFailureKind)
// Sort non-surrogates before surrogates.
return !L->IsSurrogate && R->IsSurrogate;
// Sort candidates requiring fewer parameters than there were
// arguments given after candidates requiring more parameters
// than there were arguments given.
- return L->FailureKind == ovl_fail_too_many_arguments;
+ return LFailureKind == ovl_fail_too_many_arguments;
}
return LDist < RDist;
}
return false;
}
- if (R->FailureKind == ovl_fail_too_many_arguments ||
- R->FailureKind == ovl_fail_too_few_arguments)
+ if (RFailureKind == ovl_fail_too_many_arguments ||
+ RFailureKind == ovl_fail_too_few_arguments)
return true;
// 2. Bad conversions come first and are ordered by the number
// of bad conversions and quality of good conversions.
- if (L->FailureKind == ovl_fail_bad_conversion) {
- if (R->FailureKind != ovl_fail_bad_conversion)
+ if (LFailureKind == ovl_fail_bad_conversion) {
+ if (RFailureKind != ovl_fail_bad_conversion)
return true;
// The conversion that can be fixed with a smaller number of changes,
if (leftBetter > 0) return true;
if (leftBetter < 0) return false;
- } else if (R->FailureKind == ovl_fail_bad_conversion)
+ } else if (RFailureKind == ovl_fail_bad_conversion)
return false;
- if (L->FailureKind == ovl_fail_bad_deduction) {
- if (R->FailureKind != ovl_fail_bad_deduction)
+ if (LFailureKind == ovl_fail_bad_deduction) {
+ if (RFailureKind != ovl_fail_bad_deduction)
return true;
if (L->DeductionFailure.Result != R->DeductionFailure.Result)
return RankDeductionFailure(L->DeductionFailure)
< RankDeductionFailure(R->DeductionFailure);
- } else if (R->FailureKind == ovl_fail_bad_deduction)
+ } else if (RFailureKind == ovl_fail_bad_deduction)
return false;
// TODO: others?
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
- if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+ if (Cand->FailureKind != ovl_fail_bad_conversion)
+ return;
// We only want the FixIts if all the arguments can be corrected.
bool Unfixable = false;
// expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
#endif
- explicit Number(double d) : d(d) {}
+ explicit Number(double d) : d(d) {} // expected-note 2{{explicit constructor is not a candidate}}
double d;
};
Number zero(0.0f);
namespace explicit_ctor {
struct A {};
struct B { // expected-note 2{{candidate}}
- explicit B(const A&);
+ explicit B(const A&); // expected-note {{explicit constructor is not a candidate}}
};
A a;
const B &b(a); // expected-error {{no viable conversion}}
NoDefault(int);
};
struct Explicit { // expected-note 2 {{candidate}} expected-note {{here}}
- explicit Explicit(int);
+ explicit Explicit(int); // expected-note {{not a candidate}}
};
struct NoCopy {
NoCopy();
};
struct Z { // expected-note 0+ {{candidate}}
explicit Z(); // expected-note 0+ {{here}}
- explicit Z(int);
+ explicit Z(int); // expected-note {{not a candidate}}
explicit Z(int, int); // expected-note 0+ {{here}}
};
template <class T> int Eat(T); // expected-note 0+ {{candidate}}
namespace dr152 { // dr152: yes
struct A {
A(); // expected-note 0-2{{not viable}}
- explicit A(const A&);
+ explicit A(const A&); // expected-note 1-2{{not a candidate}}
};
A a1 = A();
#if __cplusplus <= 201402L
struct ExplicitCopy {
ExplicitCopy(); // expected-note 2{{not viable}}
- explicit ExplicitCopy(const ExplicitCopy&);
+ explicit ExplicitCopy(const ExplicitCopy&); // expected-note 2{{not a candidate}}
};
auto init_kind_1 = [ec(ExplicitCopy())] {};
auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching constructor}}
struct X { }; // expected-note 2{{candidate constructor}}
struct Y {
- explicit operator X() const;
+ explicit operator X() const; // expected-note {{not a candidate}}
};
void test(const Y& y) {
struct C { }; // expected-note 2 {{candidate constructor}}
struct A {
- explicit operator int() const;
- explicit operator C() const;
+ explicit operator int() const; // expected-note {{not a candidate}}
+ explicit operator C() const; // expected-note {{not a candidate}}
};
struct B {
D1 fd1() { return 1; }
struct B2 {
- explicit B2(int, int = 0, int = 0);
+ explicit B2(int, int = 0, int = 0); // expected-note {{not a candidate}}
};
struct D2 : B2 { // expected-note 2{{candidate constructor}}
using B2::B2;
#else
//expected-note@-6+ {{candidate constructor}}
//expected-note@-9+ {{candidate constructor}}
-//expected-note@-6+ {{candidate function}}
+//expected-note-re@-7+ {{explicit constructor is not a candidate{{$}}}}
+//expected-note@-7+ {{candidate function}}
+//expected-note@-7+ {{explicit conversion function is not a candidate (explicit specifier evaluates to true)}}
//CHECK: explicit{{ +}}A(
//CHECK-NEXT: explicit(false){{ +}}operator
B<false> b_false;
#else
//expected-note@-8 {{candidate template ignored}}
-//expected-note@-8+ {{explicit constructor}}
+//expected-note@-8 {{explicit constructor declared here}}
//expected-note@-15+ {{candidate constructor}}
-//expected-note@-8+ {{candidate conversion operator ignored}}
-//expected-note@-9+ {{explicit(bool) specifier resolved to true}}
-//expected-note@-12 {{explicit(bool) specifier resolved to true}}
-//expected-note@-13+ {{candidate deductiong guide ignored}}
+//expected-note@-8+ {{explicit conversion function is not a candidate (explicit specifier}}
+//expected-note@-11 {{explicit constructor is not a candidate (explicit specifier}}
//CHECK: explicit(b){{ +}}A
//CHECK: explicit(b{{ +}}^{{ +}}T::value){{ +}}operator
// expected-note@-2 {{candidate constructor (the implicit move constructor) not}}
#endif
- explicit X(Y);
+ explicit X(Y); // expected-note {{not a candidate}}
};
Y make_Y();
};
struct ExplicitConvToBool {
- explicit operator bool();
+ explicit operator bool(); // expected-note {{explicit}}
#if __cplusplus <= 199711L // C++03 or earlier modes
// expected-warning@-2{{explicit conversion functions are a C++11 extension}}
#endif
void accepts_bool(bool) { } // expected-note{{candidate function}}
struct ExplicitConvToRef {
- explicit operator int&();
+ explicit operator int&(); // expected-note {{explicit}}
#if (__cplusplus <= 199711L) // C++03 or earlier modes
// expected-warning@-2{{explicit conversion functions are a C++11 extension}}
#endif
}
void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
- int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'ExplicitConvToRef'}}
+ int& i1 = ecr; // expected-error{{no viable conversion from 'ExplicitConvToRef' to 'int'}}
int& i2(ecr); // okay
}
struct A { };
struct B { };
struct C {
- explicit operator A&();
+ explicit operator A&(); // expected-note {{explicit}}
#if __cplusplus <= 199711L // C++03 or earlier modes
// expected-warning@-2{{explicit conversion functions are a C++11 extension}}
#endif
#endif
public:
- explicit FromShortExplicitly(short s);
+ explicit FromShortExplicitly(short s); // expected-note {{explicit constructor is not a candidate}}
};
void explicit_constructor(short s) {
class X {
public:
- explicit X(const X&);
+ explicit X(const X&); // expected-note 2{{not a candidate}}
X(int*); // expected-note 3{{candidate constructor}}
- explicit X(float*); // expected-note {{candidate constructor}}
+ explicit X(float*); // expected-note {{candidate constructor}} expected-note 2{{not a candidate}}
};
class Y : public X { };
// expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
// expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
explicit(a == 0)
-C(int),
-C(double);
+C(int), // expected-note 2{{not a candidate}}
+C(double); // expected-note 2{{not a candidate}}
};
C<0> c0 = 0.0; // expected-error {{no viable conversion}}
struct A {
// expected-note@-1+ {{candidate constructor}}
// expected-note@-2+ {{candidate function}}
- explicit(b) A(int, int = 0);
+ explicit(b) A(int, int = 0); // expected-note {{not a candidate}}
// expected-note@-1+ {{explicit constructor declared here}}
};
// expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
template<typename T2>
explicit(a ^ is_same<T1, T2>::value)
- // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
A(T2) {}
// expected-note@-1+ {{explicit constructor declared here}}
- // expected-note@-2+ {{candidate constructor ignored}}
+ // expected-note@-2+ {{not a candidate}}
};
A<true, int> a0 = 0.0; // expected-error {{no viable conversion}}
// expected-note@-1+ {{candidate constructor}}
template<typename T>
explicit(enable_ifv<is_same<int, T>::value, a>::value)
- //expected-note@-1 {{explicit(bool) specifier resolved to true}}
A(T) {}
// expected-note@-1+ {{substitution failure}}
- // expected-note@-2 {{candidate constructor ignored}}
+ // expected-note@-2 {{not a candidate}}
// expected-note@-3 {{explicit constructor declared here}}
template<typename T, bool c = true>
explicit(enable_ifv<is_same<bool, T>::value, a>::value)
- //expected-note@-1 {{explicit(bool) specifier resolved to true}}
A(T) {}
// expected-note@-1+ {{substitution failure}}
- // expected-note@-2 {{candidate constructor ignored}}
+ // expected-note@-2 {{not a candidate}}
// expected-note@-3 {{explicit constructor declared here}}
};
template<bool a>
struct A {
- explicit(a) operator int ();
+ explicit(a) operator int (); // expected-note+ {{not a candidate}}
};
template<bool a>
struct A {
template<typename T2>
explicit(enable_ifv<is_same<B, T2>::value, a>::value)
- // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
operator T2() { return T2(); };
// expected-note@-1+ {{substitution failure}}
- // expected-note@-2+ {{candidate conversion}}
+ // expected-note@-2+ {{not a candidate}}
};
A<false> A_false;
// expected-note@-2+ {{candidate function}}
template<typename ... Ts>
explicit((is_same<T, Ts>::value && ...))
- // expected-note@-1 {{explicit(bool) specifier resolved to true}}
A(Ts...);
- // expected-note@-1 {{candidate constructor}}
+ // expected-note@-1 {{not a candidate}}
// expected-note@-2 {{explicit constructor}}
};
template<bool b>
struct Z {
explicit(b) operator X() const;
- explicit(b) operator Y() const;
- explicit(b) operator int() const;
+ explicit(b) operator Y() const; // expected-note 2{{not a candidate}}
+ explicit(b) operator int() const; // expected-note {{not a candidate}}
};
void testExplicit()
struct C {
template<typename T>
explicit(!is_same<T1, T>::value)
- // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
- operator T();
- // expected-note@-1+ {{candidate conversion operator ignored}}
+ operator T(); // expected-note+ {{explicit conversion function is not a candidate}}
};
using Bool = C<bool>;
struct A {
// expected-note@-1+ {{candidate template ignored}}
explicit(!is_same<T1, T2>::value)
- // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
A(T1 = 0, T2 = 0) {}
- // expected-note@-1 {{explicit constructor}}
- // expected-note@-2+ {{candidate deductiong guide ignored}}
+ // expected-note@-1 {{explicit constructor declared here}}
+ // expected-note@-2 2{{explicit constructor is not a candidate}}
};
A a0 = 0;
struct Str {// expected-note+ {{candidate constructor}}
template <size_t N>
- explicit(N > 7)// expected-note {{resolved to true}}
- Str(char const (&str)[N]);
+ explicit(N > 7)
+ Str(char const (&str)[N]); // expected-note {{explicit constructor is not a candidate}}
};
template <size_t N>
Str::Str(char const(&str)[N]) { }
-// expected-note@-1 {{candidate constructor}}
Str a = "short";
Str b = "not so short";// expected-error {{no viable conversion}}
-}
\ No newline at end of file
+}
// expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
#endif
- explicit Y(int);
+ explicit Y(int); // expected-note 2{{explicit constructor is not a candidate}}
};
void k(Y y = 17); // expected-error{{no viable conversion}} \
};
struct B { // expected-note+ {{candidate}}
- explicit B(int);
+ explicit B(int); // expected-note {{not a candidate}}
};
B::B(int) { } // expected-note+ {{here}}
struct Z {
explicit operator X() const;
- explicit operator Y() const;
- explicit operator int() const;
+ explicit operator Y() const; // expected-note 2{{not a candidate}}
+ explicit operator int() const; // expected-note {{not a candidate}}
};
Z z;
};
struct NotBool {
- explicit operator bool(); // expected-note {{conversion to integral type 'bool'}}
+ explicit operator bool(); // expected-note {{conversion to integral type 'bool'}} expected-note 4{{explicit conversion function is not a candidate}}
};
Bool b;
NotBool n;