[clang] c354b2e - [Clang] Add note for bad conversion when expression is pointer to forward-declared type

Zequan Wu via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 7 11:06:17 PDT 2020


Author: Zequan Wu
Date: 2020-08-07T11:06:08-07:00
New Revision: c354b2e3bfe6709ffd78d0fcd017b7e5be7a7a23

URL: https://github.com/llvm/llvm-project/commit/c354b2e3bfe6709ffd78d0fcd017b7e5be7a7a23
DIFF: https://github.com/llvm/llvm-project/commit/c354b2e3bfe6709ffd78d0fcd017b7e5be7a7a23.diff

LOG: [Clang] Add note for bad conversion when expression is pointer to forward-declared type

Differential Revision: https://reviews.llvm.org/D85390

Added: 
    clang/test/SemaCXX/pointer-forward-declared-class-conversion.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaInit.cpp
    clang/test/Modules/namespaces.cpp
    clang/test/SemaCXX/elaborated-type-specifier.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2f4eb428dfad..7185a4d6cab0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2005,6 +2005,8 @@ def err_init_conversion_failed : Error<
   "|: 
diff erent return type%
diff { ($ vs $)|}5,6"
   "|: 
diff erent qualifiers (%5 vs %6)"
   "|: 
diff erent exception specifications}4">;
+def note_forward_class_conversion : Note<"%0 is not defined, but forward "
+  "declared here; conversion would be valid if it's derived from %1">;
 
 def err_lvalue_to_rvalue_ref : Error<"rvalue reference %
diff {to type $ cannot "
   "bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">;

diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e2f67e9fd59b..f4cfae0f7d85 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -8707,6 +8707,16 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity,
     if (entity.getKind() == InitializedEntity::EK_Result)
       S.EmitRelatedResultTypeNoteForReturn(destType);
   }
+  QualType fromType = op->getType();
+  auto *fromDecl = fromType.getTypePtr()->getPointeeCXXRecordDecl();
+  auto *destDecl = destType.getTypePtr()->getPointeeCXXRecordDecl();
+  if (fromDecl && destDecl && fromDecl->getDeclKind() == Decl::CXXRecord &&
+      destDecl->getDeclKind() == Decl::CXXRecord &&
+      !fromDecl->isInvalidDecl() && !destDecl->isInvalidDecl() &&
+      !fromDecl->hasDefinition())
+    S.Diag(fromDecl->getLocation(), diag::note_forward_class_conversion)
+        << S.getASTContext().getTagDeclType(fromDecl)
+        << S.getASTContext().getTagDeclType(destDecl);
 }
 
 static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,

diff  --git a/clang/test/Modules/namespaces.cpp b/clang/test/Modules/namespaces.cpp
index 5c0e18325b0a..315b1cdeda0a 100644
--- a/clang/test/Modules/namespaces.cpp
+++ b/clang/test/Modules/namespaces.cpp
@@ -78,7 +78,8 @@ void testAnonymousNotMerged() {
 
 // expected-note at Inputs/namespaces-right.h:60 {{passing argument to parameter here}}
 // expected-note at Inputs/namespaces-right.h:67 {{passing argument to parameter here}}
-
+// expected-note at Inputs/namespaces-left.h:63 {{'N11::(anonymous namespace)::Foo' is not defined, but forward declared here; conversion would be valid if it's derived from 'N11::(anonymous namespace)::Foo'}}
+// expected-note at Inputs/namespaces-left.h:70 {{'N12::(anonymous namespace)::Foo' is not defined, but forward declared here; conversion would be valid if it's derived from 'N12::(anonymous namespace)::Foo'}}
 // Test that bringing in one name from an overload set does not hide the rest.
 void testPartialImportOfOverloadSet() {
   void (*p)() = N13::p;

diff  --git a/clang/test/SemaCXX/elaborated-type-specifier.cpp b/clang/test/SemaCXX/elaborated-type-specifier.cpp
index 3701dd7ba630..06037d865d26 100644
--- a/clang/test/SemaCXX/elaborated-type-specifier.cpp
+++ b/clang/test/SemaCXX/elaborated-type-specifier.cpp
@@ -26,7 +26,7 @@ namespace NS {
 }
 
 void test_X_elab(NS::X x) {
-  struct S4 *s4 = 0;
+  struct S4 *s4 = 0; // expected-note{{'S4' is not defined, but forward declared here; conversion would be valid if it's derived from 'NS::S4'}}
   x.test_elab2(s4); // expected-error{{cannot initialize a parameter of type 'NS::S4 *' with an lvalue of type 'struct S4 *'}}
 }
 

diff  --git a/clang/test/SemaCXX/pointer-forward-declared-class-conversion.cpp b/clang/test/SemaCXX/pointer-forward-declared-class-conversion.cpp
new file mode 100644
index 000000000000..606517b51aac
--- /dev/null
+++ b/clang/test/SemaCXX/pointer-forward-declared-class-conversion.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+class A1 {};
+class B1; // expected-note{{'B1' is not defined, but forward declared here; conversion would be valid if it's derived from 'A1'}}
+B1 *b1;
+A1 *a1 = b1; // expected-error{{cannot initialize a variable of type 'A1 *' with an lvalue of type 'B1 *'}}
+
+template <class C> class A2 {};
+template <class C> class B2;
+B2<int> *b2;
+A2<int> *a2 = b2; // expected-error{{cannot initialize a variable of type 'A2<int> *' with an lvalue of type 'B2<int> *'}}


        


More information about the cfe-commits mailing list