// 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.
template <>
class vector<bool> {};
// CHECK: ClassTemplateSpecializationDecl {{.*}} vector
// CHECK: OwnerAttr {{.*}}
// 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
// The iterator typedef is a DependentNameType.
template <typename T>
class __unordered_multimap_iterator {};
// CHECK: ClassTemplateDecl {{.*}} __unordered_multimap_iterator
// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multimap_iterator
// CHECK: TemplateArgument type 'int'
// CHECK: PointerAttr
template <typename T>
class __unordered_multimap_base {
public:
using iterator = __unordered_multimap_iterator<T>;
};
template <typename T>
class unordered_multimap {
// CHECK: ClassTemplateDecl {{.*}} unordered_multimap
// CHECK: OwnerAttr {{.*}}
// CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multimap
// CHECK: OwnerAttr {{.*}}
public:
using _Mybase = __unordered_multimap_base<T>;
using iterator = typename _Mybase::iterator;
};
static_assert(sizeof(unordered_multimap<int>::iterator), ""); // Force instantiation.
// The canonical declaration of the iterator template is not its definition.
template <typename T>
class __unordered_multiset_iterator;
// CHECK: ClassTemplateDecl {{.*}} __unordered_multiset_iterator
// CHECK: PointerAttr
// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multiset_iterator
// CHECK: TemplateArgument type 'int'
// CHECK: PointerAttr
template <typename T>
class __unordered_multiset_iterator {
// CHECK: ClassTemplateDecl {{.*}} prev {{.*}} __unordered_multiset_iterator
// CHECK: PointerAttr
};
template <typename T>
class unordered_multiset {
// CHECK: ClassTemplateDecl {{.*}} unordered_multiset
// CHECK: OwnerAttr {{.*}}
// CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multiset
// CHECK: OwnerAttr {{.*}}
public:
using iterator = __unordered_multiset_iterator<T>;
};
static_assert(sizeof(unordered_multiset<int>::iterator), ""); // Force instantiation.
// 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
using size_t = unsigned;
inline constexpr size_t dynamic_extent = -1;
template <typename _Tp, size_t _Extent = dynamic_extent>
class span;
// CHECK: CXXRecordDecl {{.*}} span
// CHECK: PointerAttr {{.*}}
template <typename _Tp>
struct span<_Tp, dynamic_extent> {};
// CHECK: ClassTemplatePartialSpecializationDecl {{.*}} span
// CHECK: PointerAttr {{.*}}
} // namespace std
namespace user {
// If a class is not in the std namespace, we don't infer the attributes.
class any {
};
} // namespace user