[clang] Bug 17456 cast diagnostic

Richard Smith richard at metafoo.co.uk
Fri Jan 23 13:49:15 PST 2015


On Fri, Jan 23, 2015 at 12:37 PM, Nathan Sidwell <nathan at acm.org> wrote:
> Richard,
> I think this is the remaining patch of mine waiting for review.
>
> The original post is:
> http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20141201/119455.html
> but I duplicate the description here.  This updated patch fixes formatting,
> tabs and tweaks the error text, but otherwise is the same as the earlier
> posting.
>
> The patch addresses 17456, which is a desire for failed casts involving
> classes to give better diagnostic. see
> http://llvm.org/bugs/show_bug.cgi?id=17456

Thanks! This seems like a nice improvement to the diagnostics.

> Rather than a plain 'cannot cast' error, this patch changes things to:
>
> 1) for static cast from 'A *' to 'B *'  where T & S are classes, give
> 'static_cast from 'A *' to unrelated hierarchy 'B *' is not allowed'
>
> 2) where a cast fails and involves incomplete classes (directly or as a
> pointer), it also notes that the class is incomplete.  For instance:
>
> 17456.cc:6:10: error: static_cast from 'A *' to unrelated hierarchy 'B *' is
> not allowed

How about "static_cast from 'A *' to type 'B *' that is not related by
inheritance is not allowed"? As it stands, it sounds like you're
calling the type 'B *' a hierarchy. Also, consider:

  struct A {};
  struct B {};
  struct C : A, B {};

Here, A * and B * are not in unrelated hierarchies, so I'd prefer
something like "not related by inheritance" or "neither a base nor
derived class".

While here, please give err_bad_cxx_cast_unrelated a slightly more
specific name; [...]unrelated_class or similar?

>    return static_cast<B*>(arg);
>           ^~~~~~~~~~~~~~~~~~~~
> 17456.cc:3:8: note: 'B' is incomplete
> struct B;
>
>
> The test suite already had applicable cases,  so this patch just adjusts
> those
> tests.

+  // Detect if types are incomplete, and note it.
+  QualType Type = destType;
+  if (auto Ptr = Type->getAs<PointerType> ())
+    Type = Ptr->getPointeeType ();
+  if (auto Rec = Type->getAs<RecordType> ()) {
+    auto Decl = Rec->getAsCXXRecordDecl ();
+    if (!Decl->isCompleteDefinition ())
+      S.Diag (Decl->getLocation (), diag::note_type_incomplete)
+        << Decl->getDeclName ();
+  }
+
+  Type = src->getType();
+  if (auto Ptr = Type->getAs<PointerType> ())
+    Type = Ptr->getPointeeType ();
+  if (auto Rec = Type->getAs<RecordType> ()) {
+    auto Decl = Rec->getAsCXXRecordDecl ();
+    if (!Decl->isCompleteDefinition ())
+      S.Diag (Decl->getLocation (), diag::note_type_incomplete)
+        << Decl->getDeclName ();
+  }

I think we should only do this if we're casting to and from a class
type; I don't think it's useful to point out that T is an incomplete
type in:

  struct T *p;
  int *q = static_cast<int*>(p);

... since there is no way that completing the type of T would change
the outcome.

Also, we should produce a similar "unrelated hierarchy" diagnostic and
"incomplete" note when casting to a reference to incomplete class type
or casting from an lvalue of incomplete class type.

Finally, trivial formatting things:
 * remove the space before the parens in the function calls above.
(clang-format is a useful tool for consistently applying our preferred
formatting.)
 * put the && on the previous line when it's used in a line continuation:

+      if (SrcPointer->getPointeeType()->getAs<RecordType>()
+          && DestPointer->getPointeeType()->getAs<RecordType>())



More information about the cfe-commits mailing list