PR31606: Generalize our tentative DR resolution for inheriting copy/move
constructors to better match the pre-P0136R1 behavior. llvm-svn: 291955
This commit is contained in:
parent
7d88275577
commit
836a3b416d
|
@ -3344,8 +3344,8 @@ def note_ovl_candidate : Note<"candidate "
|
||||||
def note_ovl_candidate_inherited_constructor : Note<
|
def note_ovl_candidate_inherited_constructor : Note<
|
||||||
"constructor from base class %0 inherited here">;
|
"constructor from base class %0 inherited here">;
|
||||||
def note_ovl_candidate_inherited_constructor_slice : Note<
|
def note_ovl_candidate_inherited_constructor_slice : Note<
|
||||||
"constructor inherited from base class cannot be used to initialize from "
|
"candidate %select{constructor|template}0 ignored: "
|
||||||
"an argument of the derived class type">;
|
"inherited constructor cannot be used to %select{copy|move}1 object">;
|
||||||
def note_ovl_candidate_illegal_constructor : Note<
|
def note_ovl_candidate_illegal_constructor : Note<
|
||||||
"candidate %select{constructor|template}0 ignored: "
|
"candidate %select{constructor|template}0 ignored: "
|
||||||
"instantiation %select{takes|would take}0 its own class type by value">;
|
"instantiation %select{takes|would take}0 its own class type by value">;
|
||||||
|
|
|
@ -5944,6 +5944,28 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||||
Candidate.FailureKind = ovl_fail_illegal_constructor;
|
Candidate.FailureKind = ovl_fail_illegal_constructor;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C++ [over.match.funcs]p8: (proposed DR resolution)
|
||||||
|
// A constructor inherited from class type C that has a first parameter
|
||||||
|
// of type "reference to P" (including such a constructor instantiated
|
||||||
|
// from a template) is excluded from the set of candidate functions when
|
||||||
|
// constructing an object of type cv D if the argument list has exactly
|
||||||
|
// one argument and D is reference-related to P and P is reference-related
|
||||||
|
// to C.
|
||||||
|
auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl.getDecl());
|
||||||
|
if (Shadow && Args.size() == 1 && Constructor->getNumParams() >= 1 &&
|
||||||
|
Constructor->getParamDecl(0)->getType()->isReferenceType()) {
|
||||||
|
QualType P = Constructor->getParamDecl(0)->getType()->getPointeeType();
|
||||||
|
QualType C = Context.getRecordType(Constructor->getParent());
|
||||||
|
QualType D = Context.getRecordType(Shadow->getParent());
|
||||||
|
SourceLocation Loc = Args.front()->getExprLoc();
|
||||||
|
if ((Context.hasSameUnqualifiedType(P, C) || IsDerivedFrom(Loc, P, C)) &&
|
||||||
|
(Context.hasSameUnqualifiedType(D, P) || IsDerivedFrom(Loc, D, P))) {
|
||||||
|
Candidate.Viable = false;
|
||||||
|
Candidate.FailureKind = ovl_fail_inhctor_slice;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NumParams = Proto->getNumParams();
|
unsigned NumParams = Proto->getNumParams();
|
||||||
|
@ -6016,31 +6038,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++ [over.best.ics]p4+: (proposed DR resolution)
|
|
||||||
// If the target is the first parameter of an inherited constructor when
|
|
||||||
// constructing an object of type C with an argument list that has exactly
|
|
||||||
// one expression, an implicit conversion sequence cannot be formed if C is
|
|
||||||
// reference-related to the type that the argument would have after the
|
|
||||||
// application of the user-defined conversion (if any) and before the final
|
|
||||||
// standard conversion sequence.
|
|
||||||
auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl.getDecl());
|
|
||||||
if (Shadow && Args.size() == 1 && !isa<InitListExpr>(Args.front())) {
|
|
||||||
bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion;
|
|
||||||
QualType ConvertedArgumentType = Args.front()->getType();
|
|
||||||
if (Candidate.Conversions[0].isUserDefined())
|
|
||||||
ConvertedArgumentType =
|
|
||||||
Candidate.Conversions[0].UserDefined.After.getFromType();
|
|
||||||
if (CompareReferenceRelationship(Args.front()->getLocStart(),
|
|
||||||
Context.getRecordType(Shadow->getParent()),
|
|
||||||
ConvertedArgumentType, DerivedToBase,
|
|
||||||
ObjCConversion,
|
|
||||||
ObjCLifetimeConversion) >= Ref_Related) {
|
|
||||||
Candidate.Viable = false;
|
|
||||||
Candidate.FailureKind = ovl_fail_inhctor_slice;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
|
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
|
||||||
Candidate.Viable = false;
|
Candidate.Viable = false;
|
||||||
Candidate.FailureKind = ovl_fail_enable_if;
|
Candidate.FailureKind = ovl_fail_enable_if;
|
||||||
|
@ -10222,8 +10219,13 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||||
return DiagnoseOpenCLExtensionDisabled(S, Cand);
|
return DiagnoseOpenCLExtensionDisabled(S, Cand);
|
||||||
|
|
||||||
case ovl_fail_inhctor_slice:
|
case ovl_fail_inhctor_slice:
|
||||||
|
// It's generally not interesting to note copy/move constructors here.
|
||||||
|
if (cast<CXXConstructorDecl>(Fn)->isCopyOrMoveConstructor())
|
||||||
|
return;
|
||||||
S.Diag(Fn->getLocation(),
|
S.Diag(Fn->getLocation(),
|
||||||
diag::note_ovl_candidate_inherited_constructor_slice);
|
diag::note_ovl_candidate_inherited_constructor_slice)
|
||||||
|
<< (Fn->getPrimaryTemplate() ? 1 : 0)
|
||||||
|
<< Fn->getParamDecl(0)->getType()->isRValueReferenceType();
|
||||||
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
|
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||||
|
|
||||||
struct B1 { // expected-note 2{{candidate}}
|
struct B1 {
|
||||||
B1(int); // expected-note {{candidate}}
|
B1(int); // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct B2 { // expected-note 2{{candidate}}
|
struct B2 {
|
||||||
B2(int); // expected-note {{candidate}}
|
B2(int); // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct D1 : B1, B2 { // expected-note 2{{candidate}}
|
struct D1 : B1, B2 { // expected-note 2{{candidate}}
|
||||||
using B1::B1; // expected-note 3{{inherited here}}
|
using B1::B1; // expected-note {{inherited here}}
|
||||||
using B2::B2; // expected-note 3{{inherited here}}
|
using B2::B2; // expected-note {{inherited here}}
|
||||||
};
|
};
|
||||||
D1 d1(0); // expected-error {{ambiguous}}
|
D1 d1(0); // expected-error {{ambiguous}}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace default_ctor {
|
||||||
operator D&&();
|
operator D&&();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct A { // expected-note 4{{candidate}}
|
struct A { // expected-note 2{{candidate}}
|
||||||
A(); // expected-note {{candidate}}
|
A(); // expected-note {{candidate}}
|
||||||
|
|
||||||
A(C &&); // expected-note {{candidate}}
|
A(C &&); // expected-note {{candidate}}
|
||||||
|
@ -47,7 +47,7 @@ namespace default_ctor {
|
||||||
A(convert_to_D2); // expected-note {{candidate}}
|
A(convert_to_D2); // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct B { // expected-note 4{{candidate}}
|
struct B { // expected-note 2{{candidate}}
|
||||||
B(); // expected-note {{candidate}}
|
B(); // expected-note {{candidate}}
|
||||||
|
|
||||||
B(C &&); // expected-note {{candidate}}
|
B(C &&); // expected-note {{candidate}}
|
||||||
|
@ -66,9 +66,9 @@ namespace default_ctor {
|
||||||
using B::operator=;
|
using B::operator=;
|
||||||
};
|
};
|
||||||
struct D : A, B {
|
struct D : A, B {
|
||||||
using A::A; // expected-note 5{{inherited here}}
|
using A::A; // expected-note 3{{inherited here}}
|
||||||
using A::operator=;
|
using A::operator=;
|
||||||
using B::B; // expected-note 5{{inherited here}}
|
using B::B; // expected-note 3{{inherited here}}
|
||||||
using B::operator=;
|
using B::operator=;
|
||||||
|
|
||||||
D(int);
|
D(int);
|
||||||
|
@ -93,13 +93,13 @@ namespace default_ctor {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Y;
|
struct Y;
|
||||||
struct X { // expected-note 2{{candidate}}
|
struct X {
|
||||||
X();
|
X();
|
||||||
X(volatile Y &); // expected-note {{constructor inherited from base class cannot be used to initialize from an argument of the derived class type}}
|
X(volatile Y &); // expected-note 3{{inherited constructor cannot be used to copy object}}
|
||||||
} x;
|
} x;
|
||||||
struct Y : X { using X::X; } volatile y; // expected-note 2{{candidate}}
|
struct Y : X { using X::X; } volatile y;
|
||||||
struct Z : Y { using Y::Y; } volatile z; // expected-note 3{{candidate}} expected-note 5{{inherited here}}
|
struct Z : Y { using Y::Y; } volatile z; // expected-note 4{{no known conversion}} expected-note 2{{would lose volatile}} expected-note 3{{requires 0}} expected-note 3{{inherited here}}
|
||||||
Z z1(x); // ok
|
Z z1(x); // expected-error {{no match}}
|
||||||
Z z2(y); // ok, Z is not reference-related to type of y
|
Z z2(y); // expected-error {{no match}}
|
||||||
Z z3(z); // expected-error {{no match}}
|
Z z3(z); // expected-error {{no match}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,13 +134,13 @@ ExplicitDefaultedAggr eda2{};
|
||||||
|
|
||||||
struct DefaultedBase {
|
struct DefaultedBase {
|
||||||
int n;
|
int n;
|
||||||
DefaultedBase() = default; // expected-note 0+ {{candidate}}
|
DefaultedBase() = default;
|
||||||
DefaultedBase(DefaultedBase const&) = default; // expected-note 0+ {{candidate}}
|
DefaultedBase(DefaultedBase const&) = default;
|
||||||
DefaultedBase(DefaultedBase &&) = default; // expected-note 0+ {{candidate}}
|
DefaultedBase(DefaultedBase &&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InheritingConstructors : DefaultedBase { // expected-note 3 {{candidate}}
|
struct InheritingConstructors : DefaultedBase { // expected-note 3 {{candidate}}
|
||||||
using DefaultedBase::DefaultedBase; // expected-note 2 {{inherited here}}
|
using DefaultedBase::DefaultedBase;
|
||||||
};
|
};
|
||||||
InheritingConstructors ic = { 42 }; // expected-error {{no matching constructor}}
|
InheritingConstructors ic = { 42 }; // expected-error {{no matching constructor}}
|
||||||
|
|
||||||
|
|
|
@ -71,14 +71,14 @@ namespace dr1638 { // dr1638: yes
|
||||||
|
|
||||||
namespace dr1645 { // dr1645: 3.9
|
namespace dr1645 { // dr1645: 3.9
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
struct A { // expected-note 2{{candidate}}
|
struct A {
|
||||||
constexpr A(int, float = 0); // expected-note 2{{candidate}}
|
constexpr A(int, float = 0); // expected-note 2{{candidate}}
|
||||||
explicit A(int, int = 0); // expected-note 2{{candidate}}
|
explicit A(int, int = 0); // expected-note 2{{candidate}}
|
||||||
A(int, int, int = 0) = delete; // expected-note {{candidate}}
|
A(int, int, int = 0) = delete; // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct B : A { // expected-note 2{{candidate}}
|
struct B : A { // expected-note 2{{candidate}}
|
||||||
using A::A; // expected-note 7{{inherited here}}
|
using A::A; // expected-note 5{{inherited here}}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr B a(0); // expected-error {{ambiguous}}
|
constexpr B a(0); // expected-error {{ambiguous}}
|
||||||
|
|
|
@ -138,18 +138,21 @@ namespace dr1959 { // dr1959: 3.9
|
||||||
struct c;
|
struct c;
|
||||||
struct a {
|
struct a {
|
||||||
a() = default;
|
a() = default;
|
||||||
a(const a &) = delete; // expected-note 2{{deleted}}
|
a(const a &) = delete; // expected-note {{deleted}}
|
||||||
a(const b &) = delete; // not inherited
|
a(const b &) = delete; // not inherited
|
||||||
a(c &&) = delete;
|
a(c &&) = delete; // expected-note {{not viable}}
|
||||||
template<typename T> a(T) = delete;
|
template<typename T> a(T) = delete; // expected-note {{would take its own class type by value}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct b : a { // expected-note {{copy constructor of 'b' is implicitly deleted because base class 'dr1959::a' has a deleted copy constructor}}
|
struct b : a { // expected-note {{cannot bind}} expected-note {{deleted because}}
|
||||||
using a::a;
|
using a::a; // expected-note 2{{inherited here}}
|
||||||
};
|
};
|
||||||
|
|
||||||
a x;
|
a x;
|
||||||
b y = x; // expected-error {{deleted}}
|
// FIXME: As a resolution to an open DR against P0136R0, we disallow
|
||||||
|
// use of inherited constructors to construct from a single argument
|
||||||
|
// where the base class is reference-related to the argument type.
|
||||||
|
b y = x; // expected-error {{no viable conversion}}
|
||||||
b z = z; // expected-error {{deleted}}
|
b z = z; // expected-error {{deleted}}
|
||||||
|
|
||||||
struct c : a {
|
struct c : a {
|
||||||
|
@ -158,7 +161,7 @@ namespace dr1959 { // dr1959: 3.9
|
||||||
};
|
};
|
||||||
// FIXME: As a resolution to an open DR against P0136R0, we disallow
|
// FIXME: As a resolution to an open DR against P0136R0, we disallow
|
||||||
// use of inherited constructors to construct from a single argument
|
// use of inherited constructors to construct from a single argument
|
||||||
// where the derived class is reference-related to its type.
|
// where the base class is reference-related to the argument type.
|
||||||
c q(static_cast<c&&>(q));
|
c q(static_cast<c&&>(q));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
|
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
|
||||||
// for the wording that used to be there.
|
// for the wording that used to be there.
|
||||||
|
|
||||||
struct A { // expected-note 8{{candidate is the implicit}}
|
struct A { // expected-note 4{{candidate is the implicit}}
|
||||||
A(...); // expected-note 4{{candidate constructor}} expected-note 4{{candidate inherited constructor}}
|
A(...); // expected-note 4{{candidate constructor}} expected-note 4{{candidate inherited constructor}}
|
||||||
A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}}
|
A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}}
|
||||||
A(int = 0, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}}
|
A(int = 0, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}}
|
||||||
|
@ -15,7 +15,7 @@ struct A { // expected-note 8{{candidate is the implicit}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct B : A { // expected-note 4{{candidate is the implicit}}
|
struct B : A { // expected-note 4{{candidate is the implicit}}
|
||||||
using A::A; // expected-note 19{{inherited here}}
|
using A::A; // expected-note 15{{inherited here}}
|
||||||
B(void*);
|
B(void*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,21 +14,21 @@ D1 d1a(1), d1b(1, 1);
|
||||||
|
|
||||||
D1 fd1() { return 1; }
|
D1 fd1() { return 1; }
|
||||||
|
|
||||||
struct B2 { // expected-note 2{{candidate}}
|
struct B2 {
|
||||||
explicit B2(int, int = 0, int = 0);
|
explicit B2(int, int = 0, int = 0);
|
||||||
};
|
};
|
||||||
struct D2 : B2 { // expected-note 2{{candidate constructor}}
|
struct D2 : B2 { // expected-note 2{{candidate constructor}}
|
||||||
using B2::B2; // expected-note 2{{inherited here}}
|
using B2::B2;
|
||||||
};
|
};
|
||||||
D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
|
D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
|
||||||
|
|
||||||
D2 fd2() { return 1; } // expected-error {{no viable conversion}}
|
D2 fd2() { return 1; } // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
struct B3 { // expected-note 2{{candidate}}
|
struct B3 {
|
||||||
B3(void*); // expected-note {{candidate}}
|
B3(void*); // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
struct D3 : B3 { // expected-note 2{{candidate constructor}}
|
struct D3 : B3 { // expected-note 2{{candidate constructor}}
|
||||||
using B3::B3; // expected-note 3{{inherited here}}
|
using B3::B3; // expected-note {{inherited here}}
|
||||||
};
|
};
|
||||||
D3 fd3() { return 1; } // expected-error {{no viable conversion}}
|
D3 fd3() { return 1; } // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
|
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
|
||||||
// for the wording that used to be there.
|
// for the wording that used to be there.
|
||||||
|
|
||||||
struct B1 { // expected-note 2{{candidate}}
|
struct B1 {
|
||||||
B1(int); // expected-note {{candidate}}
|
B1(int); // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
struct B2 { // expected-note 2{{candidate}}
|
struct B2 {
|
||||||
B2(int); // expected-note {{candidate}}
|
B2(int); // expected-note {{candidate}}
|
||||||
};
|
};
|
||||||
struct D1 : B1, B2 { // expected-note 2{{candidate}}
|
struct D1 : B1, B2 { // expected-note 2{{candidate}}
|
||||||
using B1::B1; // expected-note 3{{inherited here}}
|
using B1::B1; // expected-note {{inherited here}}
|
||||||
using B2::B2; // expected-note 3{{inherited here}}
|
using B2::B2; // expected-note {{inherited here}}
|
||||||
};
|
};
|
||||||
struct D2 : B1, B2 {
|
struct D2 : B1, B2 {
|
||||||
using B1::B1;
|
using B1::B1;
|
||||||
|
|
|
@ -56,9 +56,9 @@ namespace InvalidConstruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ExplicitConv {
|
namespace ExplicitConv {
|
||||||
struct B {}; // expected-note 2{{candidate}}
|
struct B {};
|
||||||
struct D : B { // expected-note 3{{candidate}}
|
struct D : B { // expected-note 3{{candidate}}
|
||||||
using B::B; // expected-note 2{{inherited}}
|
using B::B;
|
||||||
};
|
};
|
||||||
struct X { explicit operator B(); } x;
|
struct X { explicit operator B(); } x;
|
||||||
struct Y { explicit operator D(); } y;
|
struct Y { explicit operator D(); } y;
|
||||||
|
@ -68,19 +68,40 @@ namespace ExplicitConv {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NestedListInit {
|
namespace NestedListInit {
|
||||||
struct B { B(); } b; // expected-note 5{{candidate}}
|
struct B { B(); } b; // expected-note 3{{candidate}}
|
||||||
struct D : B { // expected-note 3{{candidate}}
|
struct D : B { // expected-note 14{{not viable}}
|
||||||
using B::B; // expected-note 2{{inherited}}
|
using B::B;
|
||||||
};
|
};
|
||||||
// This is a bit weird. We're allowed one pair of braces for overload
|
// This is a bit weird. We're allowed one pair of braces for overload
|
||||||
// resolution, and one more pair of braces due to [over.ics.list]/2.
|
// resolution, and one more pair of braces due to [over.ics.list]/2.
|
||||||
B b1 = {b};
|
B b1 = {b};
|
||||||
B b2 = {{b}};
|
B b2 = {{b}};
|
||||||
B b3 = {{{b}}}; // expected-error {{no match}}
|
B b3 = {{{b}}}; // expected-error {{no match}}
|
||||||
// This is the same, but we get one call to D's version of B::B(const B&)
|
// Per a proposed defect resolution, we don't get to call
|
||||||
// before the two permitted calls to D::D(D&&).
|
// D's version of B::B(const B&) here.
|
||||||
D d1 = {b};
|
D d0 = b; // expected-error {{no viable conversion}}
|
||||||
D d2 = {{b}};
|
D d1 = {b}; // expected-error {{no match}}
|
||||||
D d3 = {{{b}}};
|
D d2 = {{b}}; // expected-error {{no match}}
|
||||||
|
D d3 = {{{b}}}; // expected-error {{no match}}
|
||||||
D d4 = {{{{b}}}}; // expected-error {{no match}}
|
D d4 = {{{{b}}}}; // expected-error {{no match}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PR31606 {
|
||||||
|
// PR31606: as part of a proposed defect resolution, do not consider
|
||||||
|
// inherited constructors that would be copy constructors for any class
|
||||||
|
// between the declaring class and the constructed class (inclusive).
|
||||||
|
struct Base {};
|
||||||
|
|
||||||
|
struct A : Base {
|
||||||
|
using Base::Base;
|
||||||
|
bool operator==(A const &) const; // expected-note {{no known conversion from 'PR31606::B' to 'const PR31606::A' for 1st argument}}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B : Base {
|
||||||
|
using Base::Base;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool a = A{} == A{};
|
||||||
|
// Note, we do *not* allow operator=='s argument to use the inherited A::A(Base&&) constructor to construct from B{}.
|
||||||
|
bool b = A{} == B{}; // expected-error {{invalid operands}}
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ void test_Unexpanded() {
|
||||||
|
|
||||||
// Test using non-type members from pack of base classes.
|
// Test using non-type members from pack of base classes.
|
||||||
template<typename ...T> struct A : T... { // expected-note 2{{candidate}}
|
template<typename ...T> struct A : T... { // expected-note 2{{candidate}}
|
||||||
using T::T ...; // expected-note 6{{inherited here}}
|
using T::T ...; // expected-note 2{{inherited here}}
|
||||||
using T::operator() ...;
|
using T::operator() ...;
|
||||||
using T::operator T* ...;
|
using T::operator T* ...;
|
||||||
using T::h ...;
|
using T::h ...;
|
||||||
|
@ -29,7 +29,7 @@ template<typename ...T> struct A : T... { // expected-note 2{{candidate}}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace test_A {
|
namespace test_A {
|
||||||
struct X { // expected-note 2{{candidate}}
|
struct X {
|
||||||
X();
|
X();
|
||||||
X(int); // expected-note {{candidate}}
|
X(int); // expected-note {{candidate}}
|
||||||
void operator()(int); // expected-note 2{{candidate}}
|
void operator()(int); // expected-note 2{{candidate}}
|
||||||
|
@ -43,7 +43,7 @@ namespace test_A {
|
||||||
operator Y *();
|
operator Y *();
|
||||||
void h(int, int); // expected-note {{not viable}}
|
void h(int, int); // expected-note {{not viable}}
|
||||||
};
|
};
|
||||||
struct Z { // expected-note 2{{candidate}}
|
struct Z {
|
||||||
Z();
|
Z();
|
||||||
Z(int); // expected-note {{candidate}}
|
Z(int); // expected-note {{candidate}}
|
||||||
void operator()(int); // expected-note 2{{candidate}}
|
void operator()(int); // expected-note 2{{candidate}}
|
||||||
|
|
Loading…
Reference in New Issue