def note_ovl_candidate_inherited_constructor : Note<
"constructor from base class %0 inherited here">;
def note_ovl_candidate_inherited_constructor_slice : Note<
- "constructor inherited from base class cannot be used to initialize from "
- "an argument of the derived class type">;
+ "candidate %select{constructor|template}0 ignored: "
+ "inherited constructor cannot be used to %select{copy|move}1 object">;
def note_ovl_candidate_illegal_constructor : Note<
"candidate %select{constructor|template}0 ignored: "
"instantiation %select{takes|would take}0 its own class type by value">;
Candidate.FailureKind = ovl_fail_illegal_constructor;
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();
}
}
- // 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)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
return DiagnoseOpenCLExtensionDisabled(S, Cand);
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(),
- 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);
return;
// RUN: %clang_cc1 -std=c++11 -verify %s
-struct B1 { // expected-note 2{{candidate}}
+struct B1 {
B1(int); // expected-note {{candidate}}
};
-struct B2 { // expected-note 2{{candidate}}
+struct B2 {
B2(int); // expected-note {{candidate}}
};
struct D1 : B1, B2 { // expected-note 2{{candidate}}
- using B1::B1; // expected-note 3{{inherited here}}
- using B2::B2; // expected-note 3{{inherited here}}
+ using B1::B1; // expected-note {{inherited here}}
+ using B2::B2; // expected-note {{inherited here}}
};
D1 d1(0); // expected-error {{ambiguous}}
operator D&&();
};
- struct A { // expected-note 4{{candidate}}
+ struct A { // expected-note 2{{candidate}}
A(); // expected-note {{candidate}}
A(C &&); // 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(C &&); // expected-note {{candidate}}
using B::operator=;
};
struct D : A, B {
- using A::A; // expected-note 5{{inherited here}}
+ using A::A; // expected-note 3{{inherited here}}
using A::operator=;
- using B::B; // expected-note 5{{inherited here}}
+ using B::B; // expected-note 3{{inherited here}}
using B::operator=;
D(int);
}
struct Y;
- struct X { // expected-note 2{{candidate}}
+ struct 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;
- struct Y : X { using X::X; } volatile y; // expected-note 2{{candidate}}
- struct Z : Y { using Y::Y; } volatile z; // expected-note 3{{candidate}} expected-note 5{{inherited here}}
- Z z1(x); // ok
- Z z2(y); // ok, Z is not reference-related to type of y
+ struct Y : X { using X::X; } volatile y;
+ 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); // expected-error {{no match}}
+ Z z2(y); // expected-error {{no match}}
Z z3(z); // expected-error {{no match}}
}
struct DefaultedBase {
int n;
- DefaultedBase() = default; // expected-note 0+ {{candidate}}
- DefaultedBase(DefaultedBase const&) = default; // expected-note 0+ {{candidate}}
- DefaultedBase(DefaultedBase &&) = default; // expected-note 0+ {{candidate}}
+ DefaultedBase() = default;
+ DefaultedBase(DefaultedBase const&) = default;
+ DefaultedBase(DefaultedBase &&) = default;
};
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}}
namespace dr1645 { // dr1645: 3.9
#if __cplusplus >= 201103L
- struct A { // expected-note 2{{candidate}}
+ struct A {
constexpr A(int, float = 0); // expected-note 2{{candidate}}
explicit A(int, int = 0); // expected-note 2{{candidate}}
A(int, int, int = 0) = delete; // expected-note {{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}}
struct c;
struct a {
a() = default;
- a(const a &) = delete; // expected-note 2{{deleted}}
+ a(const a &) = delete; // expected-note {{deleted}}
a(const b &) = delete; // not inherited
- a(c &&) = delete;
- template<typename T> a(T) = delete;
+ a(c &&) = delete; // expected-note {{not viable}}
+ 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}}
- using a::a;
+ struct b : a { // expected-note {{cannot bind}} expected-note {{deleted because}}
+ using a::a; // expected-note 2{{inherited here}}
};
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}}
struct c : a {
};
// FIXME: As a resolution to an open DR against P0136R0, we disallow
// 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));
#endif
}
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
// 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(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}}
};
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*);
};
D1 fd1() { return 1; }
-struct B2 { // expected-note 2{{candidate}}
+struct B2 {
explicit B2(int, int = 0, int = 0);
};
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 fd2() { return 1; } // expected-error {{no viable conversion}}
-struct B3 { // expected-note 2{{candidate}}
+struct B3 {
B3(void*); // expected-note {{candidate}}
};
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}}
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
// for the wording that used to be there.
-struct B1 { // expected-note 2{{candidate}}
+struct B1 {
B1(int); // expected-note {{candidate}}
};
-struct B2 { // expected-note 2{{candidate}}
+struct B2 {
B2(int); // expected-note {{candidate}}
};
struct D1 : B1, B2 { // expected-note 2{{candidate}}
- using B1::B1; // expected-note 3{{inherited here}}
- using B2::B2; // expected-note 3{{inherited here}}
+ using B1::B1; // expected-note {{inherited here}}
+ using B2::B2; // expected-note {{inherited here}}
};
struct D2 : B1, B2 {
using B1::B1;
}
namespace ExplicitConv {
- struct B {}; // expected-note 2{{candidate}}
+ struct B {};
struct D : B { // expected-note 3{{candidate}}
- using B::B; // expected-note 2{{inherited}}
+ using B::B;
};
struct X { explicit operator B(); } x;
struct Y { explicit operator D(); } y;
}
namespace NestedListInit {
- struct B { B(); } b; // expected-note 5{{candidate}}
- struct D : B { // expected-note 3{{candidate}}
- using B::B; // expected-note 2{{inherited}}
+ struct B { B(); } b; // expected-note 3{{candidate}}
+ struct D : B { // expected-note 14{{not viable}}
+ using B::B;
};
// 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.
B b1 = {b};
B b2 = {{b}};
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&)
- // before the two permitted calls to D::D(D&&).
- D d1 = {b};
- D d2 = {{b}};
- D d3 = {{{b}}};
+ // Per a proposed defect resolution, we don't get to call
+ // D's version of B::B(const B&) here.
+ D d0 = b; // expected-error {{no viable conversion}}
+ D d1 = {b}; // expected-error {{no match}}
+ D d2 = {{b}}; // expected-error {{no match}}
+ D d3 = {{{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}}
+}
// Test using non-type members from pack of base classes.
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 T* ...;
using T::h ...;
};
namespace test_A {
- struct X { // expected-note 2{{candidate}}
+ struct X {
X();
X(int); // expected-note {{candidate}}
void operator()(int); // expected-note 2{{candidate}}
operator Y *();
void h(int, int); // expected-note {{not viable}}
};
- struct Z { // expected-note 2{{candidate}}
+ struct Z {
Z();
Z(int); // expected-note {{candidate}}
void operator()(int); // expected-note 2{{candidate}}