forked from OSchip/llvm-project
PR30305: Implement proposed DR resolution to prevent slicing via inherited constructor.
The rule we use is that a construction of a class type T from an argument of type U cannot use an inherited constructor if U is the same as T or is derived from T (or if the initialization would first convert it to such a type). This (approximately) matches the rule in use by GCC, and matches the current proposed DR resolution. llvm-svn: 291403
This commit is contained in:
parent
f51ba1e3da
commit
f9c59b7122
|
@ -3333,6 +3333,9 @@ def note_ovl_candidate : Note<"candidate "
|
|||
|
||||
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">;
|
||||
|
|
|
@ -601,6 +601,10 @@ namespace clang {
|
|||
|
||||
/// 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).
|
||||
|
|
|
@ -5971,6 +5971,31 @@ 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)) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_enable_if;
|
||||
|
@ -9927,6 +9952,12 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
|||
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;
|
||||
|
|
|
@ -28,14 +28,23 @@ namespace default_ctor {
|
|||
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}}
|
||||
|
@ -44,8 +53,10 @@ namespace default_ctor {
|
|||
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 {
|
||||
|
@ -75,7 +86,20 @@ namespace default_ctor {
|
|||
// 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}}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace dr1959 { // dr1959: 3.9
|
|||
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;
|
||||
};
|
||||
|
||||
|
@ -152,13 +152,14 @@ namespace dr1959 { // dr1959: 3.9
|
|||
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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue