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">;
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">;
/// This candidate was not viable because its OpenCL extension is disabled.
ovl_fail_ext_disabled,
+
+ /// This inherited constructor is not viable because it would slice the
+ /// argument.
+ ovl_fail_inhctor_slice,
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
}
}
+ // 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;
case ovl_fail_ext_disabled:
return DiagnoseOpenCLExtensionDisabled(S, Cand);
+ case ovl_fail_inhctor_slice:
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_inherited_constructor_slice);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
+ return;
+
case ovl_fail_addr_not_available: {
bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
(void)Available;
struct C;
struct D;
+ struct convert_to_D1 {
+ operator D&&();
+ };
+ struct convert_to_D2 {
+ operator D&&();
+ };
+
struct A { // expected-note 4{{candidate}}
A(); // expected-note {{candidate}}
A(C &&); // expected-note {{candidate}}
C &operator=(C&&); // expected-note {{candidate}}
- A(D &&); // expected-note {{candidate}}
+ A(D &&);
D &operator=(D&&); // expected-note {{candidate}}
+
+ A(convert_to_D2); // expected-note {{candidate}}
};
struct B { // expected-note 4{{candidate}}
B(C &&); // expected-note {{candidate}}
C &operator=(C&&); // expected-note {{candidate}}
- B(D &&); // expected-note {{candidate}}
+ B(D &&);
D &operator=(D&&); // expected-note {{candidate}}
+
+ B(convert_to_D2); // expected-note {{candidate}}
};
struct C : A, B {
// versions are inherited.
D d; // expected-error {{ambiguous}}
void f(D d) {
- D d2(static_cast<D&&>(d)); // expected-error {{ambiguous}}
+ D d2(static_cast<D&&>(d)); // ok, ignores inherited constructors
+ D d3(convert_to_D1{}); // ok, ignores inherited constructors
+ D d4(convert_to_D2{}); // expected-error {{ambiguous}}
d = static_cast<D&&>(d); // expected-error {{ambiguous}}
}
+
+ struct Y;
+ struct X { // expected-note 2{{candidate}}
+ 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;
+ 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
+ Z z3(z); // expected-error {{no match}}
}
a() = default;
a(const a &) = delete; // expected-note 2{{deleted}}
a(const b &) = delete; // not inherited
- a(c &&) = delete; // expected-note {{deleted}}
+ a(c &&) = delete;
template<typename T> a(T) = delete;
};
b y = x; // expected-error {{deleted}}
b z = z; // expected-error {{deleted}}
- // FIXME: It's not really clear that this matches the intent, but it's
- // consistent with the behavior for assignment operators.
struct c : a {
using a::a;
c(const c &);
};
- c q(static_cast<c&&>(q)); // expected-error {{call to 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 derived class is reference-related to its type.
+ c q(static_cast<c&&>(q));
#endif
}