When diagnosing the lack of a viable conversion function, also list

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.
This commit is contained in:
Richard Smith 2020-01-09 12:27:48 -08:00
parent 68c8b6c4cd
commit 2519554134
21 changed files with 204 additions and 172 deletions

View File

@ -1783,7 +1783,7 @@ public:
};
/// 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};
@ -1796,20 +1796,22 @@ public:
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 &&
@ -1817,9 +1819,7 @@ public:
}
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));

View File

@ -3871,10 +3871,9 @@ def note_ovl_candidate : Note<
"| 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<

View File

@ -732,10 +732,9 @@ class Sema;
/// 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,

View File

@ -3877,9 +3877,6 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
continue;
if (!AllowExplicit && Info.Constructor->isExplicit())
continue;
if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
continue;
@ -3951,18 +3948,16 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
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);
}
}
}
@ -4495,7 +4490,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
continue;
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
@ -4540,8 +4535,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// 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(
@ -5153,7 +5147,7 @@ static void TryUserDefinedConversion(Sema &S,
continue;
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(AllowExplicit)) {
Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
@ -5197,16 +5191,14 @@ static void TryUserDefinedConversion(Sema &S,
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);
}
}
}
@ -9778,9 +9770,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// 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

View File

@ -3320,8 +3320,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
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.
@ -3443,11 +3442,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
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) {
@ -3501,16 +3498,14 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
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);
}
}
}
@ -4543,11 +4538,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
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.
@ -6183,6 +6173,15 @@ void Sema::AddOverloadCandidate(
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;
@ -6316,15 +6315,6 @@ void Sema::AddOverloadCandidate(
}
}
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;
@ -6923,6 +6913,12 @@ void Sema::AddMethodTemplateCandidate(
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.
@ -6935,6 +6931,18 @@ void Sema::AddTemplateOverloadCandidate(
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
@ -7122,6 +7130,9 @@ void Sema::AddConversionCandidate(
// 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))
@ -7143,6 +7154,15 @@ void Sema::AddConversionCandidate(
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
@ -7267,13 +7287,6 @@ void Sema::AddConversionCandidate(
"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;
@ -7304,6 +7317,18 @@ void Sema::AddTemplateConversionCandidate(
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
@ -10764,30 +10789,36 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
}
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) {
@ -10888,7 +10919,7 @@ static void NoteFunctionCandidate(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:
@ -11053,6 +11084,23 @@ struct CompareOverloadCandidatesForDisplay {
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.
@ -11076,34 +11124,37 @@ struct CompareOverloadCandidatesForDisplay {
// 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,
@ -11141,17 +11192,17 @@ struct CompareOverloadCandidatesForDisplay {
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?
@ -11180,7 +11231,8 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
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;

View File

@ -38,7 +38,7 @@ namespace Numbers {
// 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);

View File

@ -65,7 +65,7 @@ namespace test3 {
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}}

View File

@ -5,7 +5,7 @@ struct NoDefault {
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();

View File

@ -142,7 +142,7 @@ struct Z0 { // expected-note 0+ {{candidate}}
};
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}}

View File

@ -600,7 +600,7 @@ namespace dr151 { // dr151: yes
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

View File

@ -27,7 +27,7 @@ void hiding() {
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}}

View File

@ -4,7 +4,7 @@ namespace ExplicitConv {
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) {
@ -18,8 +18,8 @@ namespace DR899 {
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 {

View File

@ -15,7 +15,7 @@ D1 d1a(1), d1b(1, 1);
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;

View File

@ -40,7 +40,9 @@ struct A {
#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
@ -73,12 +75,10 @@ B<true> b_true;
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

View File

@ -211,7 +211,7 @@ namespace smart_ptr {
// 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();

View File

@ -11,7 +11,7 @@ struct ConvToInt {
};
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
@ -45,7 +45,7 @@ void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) {
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
@ -58,14 +58,14 @@ void test_explicit_bool(ExplicitConvToBool ecb) {
}
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

View File

@ -36,7 +36,7 @@ class FromShortExplicitly { // expected-note{{candidate constructor (the implici
#endif
public:
explicit FromShortExplicitly(short s);
explicit FromShortExplicitly(short s); // expected-note {{explicit constructor is not a candidate}}
};
void explicit_constructor(short s) {

View File

@ -4,9 +4,9 @@
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 { };

View File

@ -55,8 +55,8 @@ template<int a>
// 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}}
@ -105,7 +105,7 @@ template<bool b>
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}}
};
@ -154,10 +154,9 @@ struct A {
// 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}}
@ -196,17 +195,15 @@ struct A {
// 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}}
};
@ -236,7 +233,7 @@ namespace conversion {
template<bool a>
struct A {
explicit(a) operator int ();
explicit(a) operator int (); // expected-note+ {{not a candidate}}
};
template<bool a>
@ -293,10 +290,9 @@ 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;
@ -348,9 +344,8 @@ struct A {
// 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}}
};
@ -517,8 +512,8 @@ class Y { }; // expected-note+ {{candidate constructor (the implicit}}
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()
@ -559,9 +554,7 @@ template<typename T1>
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>;
@ -684,10 +677,9 @@ template<typename T1 = int, typename T2 = int>
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;
@ -723,15 +715,14 @@ using size_t = decltype(sizeof(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}}
}
}

View File

@ -31,7 +31,7 @@ struct Y { // expected-note 2{{candidate constructor (the implicit copy construc
// 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}} \

View File

@ -7,7 +7,7 @@ struct A {
};
struct B { // expected-note+ {{candidate}}
explicit B(int);
explicit B(int); // expected-note {{not a candidate}}
};
B::B(int) { } // expected-note+ {{here}}
@ -78,8 +78,8 @@ namespace Conversion {
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;
@ -118,7 +118,7 @@ namespace Conversion {
};
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;