diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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>, DefaultIgnore; + def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -206,6 +206,24 @@ } } +namespace { +bool IsStdVector(Decl *D) { + auto *ND = dyn_cast_or_null(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(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` 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(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; } diff --git a/clang/test/Sema/warn-vector-of-incomplete-access.cpp b/clang/test/Sema/warn-vector-of-incomplete-access.cpp new file mode 100644 --- /dev/null +++ b/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 struct vector { + using size_type = unsigned; + + vector(); + ~vector(); + + unsigned size(); +}; +} + +struct Incomplete; +std::vector::size_type x; // expected-warning{{ISO C++ forbids access to member 'size_type' of 'std::vector' with incomplete type 'Incomplete'}} +std::vector 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 x; +}; + +struct WithSubtype { + struct Subtype { + std::vector x; + }; + Subtype y; + unsigned count = y.x.size(); + +};