Author: rsmith Date: Sun Jan 8 15:45:44 2017 New Revision: 291403 URL: http://llvm.org/viewvc/llvm-project?rev=291403&view=rev Log: 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. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp cfe/trunk/test/CXX/drs/dr19xx.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=291403&r1=291402&r2=291403&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Jan 8 15:45:44 2017 @@ -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">; Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=291403&r1=291402&r2=291403&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Sun Jan 8 15:45:44 2017 @@ -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). Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=291403&r1=291402&r2=291403&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Jan 8 15:45:44 2017 @@ -5971,6 +5971,31 @@ Sema::AddOverloadCandidate(FunctionDecl } } + // 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 & 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; Modified: cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp?rev=291403&r1=291402&r2=291403&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp (original) +++ cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp Sun Jan 8 15:45:44 2017 @@ -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}} } Modified: cfe/trunk/test/CXX/drs/dr19xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr19xx.cpp?rev=291403&r1=291402&r2=291403&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr19xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr19xx.cpp Sun Jan 8 15:45:44 2017 @@ -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 } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits