[PATCH] D133029: [Sema] Allow to diagnose the references to std::vector<T> with incomplete T

Ilya Biryukov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 31 08:20:03 PDT 2022


ilya-biryukov created this revision.
Herald added a project: All.
ilya-biryukov requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add a warning `-Waccess-vector-incomplete-member`.

Inspired by recent changes to libc++ that make some uses actually fail
in C++20 mode, e.g. calls to `size()` started producing errors in cases
that were fine before.

These accesses are explicitly forbidden by the standard, but end up
working in existing implementations.

The warning is disabled by default, it is intended to be enabled for
finding instances of the code that can potentially break. We intend to
use it to find candidates for cleanup before the C++20 transition.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133029

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExpr.cpp
  clang/test/Sema/warn-vector-of-incomplete-access.cpp


Index: clang/test/Sema/warn-vector-of-incomplete-access.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/warn-vector-of-incomplete-access.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -verify -Waccess-vector-incomplete-member
+
+namespace std {
+template <class T> struct vector {
+  using size_type = unsigned;
+
+  vector();
+  ~vector();
+
+  unsigned size();
+};
+}
+
+struct Incomplete;
+std::vector<Incomplete>::size_type x; // expected-warning{{ISO C++ forbids access to member 'size_type' of 'std::vector' with incomplete type 'Incomplete'}}
+std::vector<Incomplete> y; // expected-warning{{ISO C++ forbids access to member 'vector' of 'std::vector' with incomplete type 'Incomplete'}} \
+                              expected-warning{{ISO C++ forbids access to member '~vector' of 'std::vector' with incomplete type 'Incomplete'}} \
+
+// Some tricky usages that should be ok.
+struct Recursive {
+  std::vector<Recursive> x;
+};
+
+struct WithSubtype {
+  struct Subtype {
+    std::vector<WithSubtype> x;
+  };
+  Subtype y;
+  unsigned count = y.x.size();
+
+};
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -206,6 +206,24 @@
   }
 }
 
+namespace {
+bool IsStdVector(Decl *D) {
+  auto *ND = dyn_cast_or_null<NamedDecl>(D);
+  auto *Name = ND ? ND->getIdentifier() : nullptr;
+  auto *Parent = ND ? ND->getDeclContext() : nullptr;
+  return Name && Name->isStr("vector") && Parent && Parent->isStdNamespace();
+}
+
+QualType ExtractStdVectorTemplateArg(Decl* D) {
+  auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(D);
+  if (!SD) return QualType();
+  if (SD->getTemplateArgs().size() < 1) return QualType();
+  auto &A = SD->getTemplateArgs().get(0);
+  if (A.getKind() != TemplateArgument::Type) return QualType();
+  return A.getAsType();
+}
+} // namespace
+
 /// Determine whether the use of this declaration is valid, and
 /// emit any corresponding diagnostics.
 ///
@@ -392,6 +410,18 @@
     return true;
   }
 
+  // Diagnose access to members of `vector<T>` with incomplete `T`.
+  // [vector.overview]p4
+  // An incomplete type T may be used when instantiating vector if the allocator meets the allocator completeness
+  // requirements (16.5.3.5.1). T shall be complete before any member of the resulting specialization of vector is
+  // referenced.
+  if (auto *Parent = dyn_cast<Decl>(D->getDeclContext()); IsStdVector(Parent)) {
+    auto T = ExtractStdVectorTemplateArg(Parent);
+    if (!T.isNull() && T->isIncompleteType())
+      Diag(Loc, diag::warn_access_member_of_vector_of_incomplete_type)
+          << D << T;
+  }
+
   return false;
 }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8743,6 +8743,10 @@
 def note_inequality_comparison_to_or_assign : Note<
   "use '|=' to turn this inequality comparison into an or-assignment">;
 
+def warn_access_member_of_vector_of_incomplete_type : Warning<
+  "ISO C++ forbids access to member %0 of 'std::vector' with incomplete type %1">,
+  InGroup<DiagGroup<"access-vector-incomplete-member">>, DefaultIgnore;
+
 def err_incomplete_type_used_in_type_trait_expr : Error<
   "incomplete type %0 used in type trait expression">;
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D133029.456972.patch
Type: text/x-patch
Size: 3485 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20220831/288d7bc0/attachment.bin>


More information about the cfe-commits mailing list