int *getInt() { return &value; }
};
-The argument ``T`` is optional and currently ignored.
+The argument ``T`` is optional and is ignored.
This attribute may be used by analysis tools and has no effect on code
generation.
int *getInt() { return &valuePointer; }
};
-The argument ``T`` is optional and currently ignored.
+The argument ``T`` is optional and is ignored.
This attribute may be used by analysis tools and has no effect on code
generation.
ClassTemplateSpecializationDecl *BaseTemplateSpec,
SourceLocation BaseLoc);
+ /// Add gsl::Pointer attribute to std::container::iterator
+ /// \param ND The declaration that introduces the name
+ /// std::container::iterator. \param UnderlyingRecord The record named by ND.
+ void inferGslPointerAttribute(NamedDecl *ND, CXXRecordDecl *UnderlyingRecord);
+
+ /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
+ void inferGslOwnerPointerAttribute(CXXRecordDecl *Record);
+
+ /// Add [[gsl::Pointer]] attributes for std:: types.
+ void inferGslPointerAttribute(TypedefNameDecl *TD);
+
void CheckCompletedCXXClass(CXXRecordDecl *Record);
/// Check that the C++ class annoated with "trivial_abi" satisfies all the
MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
}
+template <typename Attribute>
+static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context,
+ CXXRecordDecl *Record) {
+ CXXRecordDecl *Canonical = Record->getCanonicalDecl();
+ if (Canonical->hasAttr<OwnerAttr>() || Canonical->hasAttr<PointerAttr>())
+ return;
+
+ Canonical->addAttr(::new (Context) Attribute(SourceRange{}, Context,
+ /*DerefType*/ nullptr,
+ /*Spelling=*/0));
+}
+
+void Sema::inferGslPointerAttribute(NamedDecl *ND,
+ CXXRecordDecl *UnderlyingRecord) {
+ if (!UnderlyingRecord)
+ return;
+
+ const auto *Parent = dyn_cast<CXXRecordDecl>(ND->getDeclContext());
+ if (!Parent)
+ return;
+
+ static llvm::StringSet<> Containers{
+ "array",
+ "basic_string",
+ "deque",
+ "forward_list",
+ "vector",
+ "list",
+ "map",
+ "multiset",
+ "multimap",
+ "priority_queue",
+ "queue",
+ "set",
+ "stack",
+ "unordered_set",
+ "unordered_map",
+ "unordered_multiset",
+ "unordered_multimap",
+ };
+
+ static llvm::StringSet<> Iterators{"iterator", "const_iterator",
+ "reverse_iterator",
+ "const_reverse_iterator"};
+
+ if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) &&
+ Containers.count(Parent->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context,
+ UnderlyingRecord);
+}
+
+void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) {
+
+ QualType Canonical = TD->getUnderlyingType().getCanonicalType();
+
+ CXXRecordDecl *RD = Canonical->getAsCXXRecordDecl();
+ if (!RD) {
+ if (auto *TST =
+ dyn_cast<TemplateSpecializationType>(Canonical.getTypePtr())) {
+
+ RD = dyn_cast_or_null<CXXRecordDecl>(
+ TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl());
+ }
+ }
+
+ inferGslPointerAttribute(TD, RD);
+}
+
+void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
+ static llvm::StringSet<> StdOwners{
+ "any",
+ "array",
+ "basic_regex",
+ "basic_string",
+ "deque",
+ "forward_list",
+ "vector",
+ "list",
+ "map",
+ "multiset",
+ "multimap",
+ "optional",
+ "priority_queue",
+ "queue",
+ "set",
+ "stack",
+ "unique_ptr",
+ "unordered_set",
+ "unordered_map",
+ "unordered_multiset",
+ "unordered_multimap",
+ "variant",
+ };
+ static llvm::StringSet<> StdPointers{
+ "basic_string_view",
+ "reference_wrapper",
+ "regex_iterator",
+ };
+
+ if (!Record->getIdentifier())
+ return;
+
+ // Handle classes that directly appear in std namespace.
+ if (Record->isInStdNamespace()) {
+ CXXRecordDecl *Canonical = Record->getCanonicalDecl();
+ if (Canonical->hasAttr<OwnerAttr>() || Canonical->hasAttr<PointerAttr>())
+ return;
+
+ if (StdOwners.count(Record->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<OwnerAttr>(Context, Record);
+ else if (StdPointers.count(Record->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context, Record);
+
+ return;
+ }
+
+ // Handle nested classes that could be a gsl::Pointer.
+ inferGslPointerAttribute(Record, Record);
+}
+
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
PragmaMsStackAction Action = Sema::PSK_Reset;
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(S, NewTD, Previous);
+ } else {
+ inferGslPointerAttribute(NewTD);
}
if (ShadowedDecl && !Redeclaration)
if (PrevDecl)
mergeDeclAttributes(New, PrevDecl);
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New))
+ inferGslOwnerPointerAttribute(CXXRD);
+
// If there's a #pragma GCC visibility in scope, set the visibility of this
// record.
AddPushedVisibilityAttribute(New);
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
AddPushedVisibilityAttribute(NewClass);
+ inferGslOwnerPointerAttribute(NewClass);
if (TUK != TUK_Friend) {
// Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
--- /dev/null
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+ // CHECK: CXXRecordDecl {{.*}} any
+ // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template <typename T>
+class vector {
+public:
+ class iterator {};
+ // CHECK: ClassTemplateDecl {{.*}} vector
+ // CHECK: OwnerAttr {{.*}}
+ // CHECK: CXXRecordDecl {{.*}} iterator
+ // CHECK: PointerAttr {{.*}}
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+ // CHECK: TemplateArgument type 'int'
+ // CHECK: OwnerAttr
+ // CHECK: CXXRecordDecl {{.*}} iterator
+ // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector<int>), ""); // Force instantiation.
+static_assert(sizeof(vector<int>::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template <typename T>
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template <typename T>
+class set {
+ // CHECK: ClassTemplateDecl {{.*}} set
+ // CHECK: OwnerAttr {{.*}}
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+ // CHECK: OwnerAttr {{.*}}
+public:
+ using iterator = __set_iterator<T>;
+};
+static_assert(sizeof(set<int>::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template <typename T>
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template <typename T>
+class map {
+ // CHECK: ClassTemplateDecl {{.*}} map
+ // CHECK: OwnerAttr {{.*}}
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+ // CHECK: OwnerAttr {{.*}}
+public:
+ typedef __map_iterator<T> iterator;
+};
+static_assert(sizeof(map<int>::iterator), ""); // Force instantiation.
+
+// Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
+template <typename T>
+class __unordered_map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template <typename T>
+class unordered_map {
+ // CHECK: ClassTemplateDecl {{.*}} unordered_map
+ // CHECK: OwnerAttr {{.*}}
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_map
+ // CHECK: OwnerAttr {{.*}}
+public:
+ typedef __unordered_map_iterator<T> iterator;
+};
+static_assert(sizeof(unordered_map<int>::iterator), ""); // Force instantiation.
+} // namespace inlinens
+
+// std::list has an implicit gsl::Owner attribute,
+// but explicit attributes take precedence.
+template <typename T>
+class [[gsl::Pointer]] list{};
+// CHECK: ClassTemplateDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+
+static_assert(sizeof(list<int>), ""); // Force instantiation.
+
+// Forward declared template (Owner).
+template <
+ class CharT,
+ class Traits>
+class basic_regex;
+// CHECK: ClassTemplateDecl {{.*}} basic_regex
+// CHECK: OwnerAttr {{.*}}
+
+// Forward declared template (Pointer).
+template <class T>
+class reference_wrapper;
+// CHECK: ClassTemplateDecl {{.*}} reference_wrapper
+// CHECK: PointerAttr {{.*}}
+
+class some_unknown_type;
+// CHECK: CXXRecordDecl {{.*}} some_unknown_type
+
+} // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't infer the attributes.
+class any {
+};
+} // namespace user