r291403 - PR30305: Implement proposed DR resolution to prevent slicing via inherited constructor.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 8 13:45:45 PST 2017


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
 }
 




More information about the cfe-commits mailing list