rsmith updated this revision to Diff 304984.
rsmith marked 5 inline comments as done.
rsmith added a comment.
- Address review comments.
- Extend libc++ changes to cover <regex>.
- Bugfixes from further testing.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D91311/new/
https://reviews.llvm.org/D91311
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/TypePrinter.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/SemaTemplate/attributes.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
libcxx/include/__config
libcxx/include/iosfwd
libcxx/include/regex
libcxx/include/string
libcxx/include/string_view
Index: libcxx/include/string_view
===================================================================
--- libcxx/include/string_view
+++ libcxx/include/string_view
@@ -192,7 +192,26 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template<class _CharT, class _Traits = char_traits<_CharT> >
-class _LIBCPP_TEMPLATE_VIS basic_string_view {
+ class _LIBCPP_TEMPLATE_VIS basic_string_view;
+
+typedef basic_string_view<char> string_view;
+#ifndef _LIBCPP_NO_HAS_CHAR8_T
+typedef basic_string_view<char8_t> u8string_view;
+#endif
+typedef basic_string_view<char16_t> u16string_view;
+typedef basic_string_view<char32_t> u32string_view;
+typedef basic_string_view<wchar_t> wstring_view;
+
+template<class _CharT, class _Traits>
+class
+ _LIBCPP_PREFERRED_NAME(string_view)
+#ifndef _LIBCPP_NO_HAS_CHAR8_T
+ _LIBCPP_PREFERRED_NAME(u8string_view)
+#endif
+ _LIBCPP_PREFERRED_NAME(u16string_view)
+ _LIBCPP_PREFERRED_NAME(u32string_view)
+ _LIBCPP_PREFERRED_NAME(wstring_view)
+ basic_string_view {
public:
// types
typedef _Traits traits_type;
@@ -776,14 +795,6 @@
operator<<(basic_ostream<_CharT, _Traits>& __os,
basic_string_view<_CharT, _Traits> __str);
-typedef basic_string_view<char> string_view;
-#ifndef _LIBCPP_NO_HAS_CHAR8_T
-typedef basic_string_view<char8_t> u8string_view;
-#endif
-typedef basic_string_view<char16_t> u16string_view;
-typedef basic_string_view<char32_t> u32string_view;
-typedef basic_string_view<wchar_t> wstring_view;
-
// [string.view.hash]
template<class _CharT>
struct _LIBCPP_TEMPLATE_VIS hash<basic_string_view<_CharT, char_traits<_CharT> > >
Index: libcxx/include/string
===================================================================
--- libcxx/include/string
+++ libcxx/include/string
@@ -665,8 +665,26 @@
#endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
+#ifndef _LIBCPP_NO_HAS_CHAR8_T
+typedef basic_string<char8_t> u8string;
+#endif
+
+#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
+typedef basic_string<char16_t> u16string;
+typedef basic_string<char32_t> u32string;
+#endif // _LIBCPP_HAS_NO_UNICODE_CHARS
+
template<class _CharT, class _Traits, class _Allocator>
-class _LIBCPP_TEMPLATE_VIS basic_string
+class
+ _LIBCPP_TEMPLATE_VIS
+#ifndef _LIBCPP_NO_HAS_CHAR8_T
+ _LIBCPP_PREFERRED_NAME(u8string)
+#endif
+#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
+ _LIBCPP_PREFERRED_NAME(u16string)
+ _LIBCPP_PREFERRED_NAME(u32string)
+#endif
+ basic_string
: private __basic_string_common<true>
{
public:
@@ -4301,15 +4319,6 @@
__lhs.swap(__rhs);
}
-#ifndef _LIBCPP_NO_HAS_CHAR8_T
-typedef basic_string<char8_t> u8string;
-#endif
-
-#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
-typedef basic_string<char16_t> u16string;
-typedef basic_string<char32_t> u32string;
-#endif // _LIBCPP_HAS_NO_UNICODE_CHARS
-
_LIBCPP_FUNC_VIS int stoi (const string& __str, size_t* __idx = 0, int __base = 10);
_LIBCPP_FUNC_VIS long stol (const string& __str, size_t* __idx = 0, int __base = 10);
_LIBCPP_FUNC_VIS unsigned long stoul (const string& __str, size_t* __idx = 0, int __base = 10);
Index: libcxx/include/regex
===================================================================
--- libcxx/include/regex
+++ libcxx/include/regex
@@ -2507,7 +2507,17 @@
template <class _CharT, class _Traits> class __lookahead;
template <class _CharT, class _Traits = regex_traits<_CharT> >
-class _LIBCPP_TEMPLATE_VIS basic_regex
+ class _LIBCPP_TEMPLATE_VIS basic_regex;
+
+typedef basic_regex<char> regex;
+typedef basic_regex<wchar_t> wregex;
+
+template <class _CharT, class _Traits>
+class
+ _LIBCPP_TEMPLATE_VIS
+ _LIBCPP_PREFERRED_NAME(regex)
+ _LIBCPP_PREFERRED_NAME(wregex)
+ basic_regex
{
public:
// types:
@@ -4845,13 +4855,21 @@
__end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
}
-typedef basic_regex<char> regex;
-typedef basic_regex<wchar_t> wregex;
-
// sub_match
+typedef sub_match<const char*> csub_match;
+typedef sub_match<const wchar_t*> wcsub_match;
+typedef sub_match<string::const_iterator> ssub_match;
+typedef sub_match<wstring::const_iterator> wssub_match;
+
template <class _BidirectionalIterator>
-class _LIBCPP_TEMPLATE_VIS sub_match
+class
+ _LIBCPP_TEMPLATE_VIS
+ _LIBCPP_PREFERRED_NAME(csub_match)
+ _LIBCPP_PREFERRED_NAME(wcsub_match)
+ _LIBCPP_PREFERRED_NAME(ssub_match)
+ _LIBCPP_PREFERRED_NAME(wssub_match)
+ sub_match
: public pair<_BidirectionalIterator, _BidirectionalIterator>
{
public:
@@ -4886,11 +4904,6 @@
{return str().compare(__s);}
};
-typedef sub_match<const char*> csub_match;
-typedef sub_match<const wchar_t*> wcsub_match;
-typedef sub_match<string::const_iterator> ssub_match;
-typedef sub_match<wstring::const_iterator> wssub_match;
-
template <class _BiIter>
inline _LIBCPP_INLINE_VISIBILITY
bool
@@ -5273,8 +5286,19 @@
return __os << __m.str();
}
+typedef match_results<const char*> cmatch;
+typedef match_results<const wchar_t*> wcmatch;
+typedef match_results<string::const_iterator> smatch;
+typedef match_results<wstring::const_iterator> wsmatch;
+
template <class _BidirectionalIterator, class _Allocator>
-class _LIBCPP_TEMPLATE_VIS match_results
+class
+ _LIBCPP_TEMPLATE_VIS
+ _LIBCPP_PREFERRED_NAME(cmatch)
+ _LIBCPP_PREFERRED_NAME(wcmatch)
+ _LIBCPP_PREFERRED_NAME(smatch)
+ _LIBCPP_PREFERRED_NAME(wsmatch)
+ match_results
{
public:
typedef _Allocator allocator_type;
@@ -5594,11 +5618,6 @@
swap(__ready_, __m.__ready_);
}
-typedef match_results<const char*> cmatch;
-typedef match_results<const wchar_t*> wcmatch;
-typedef match_results<string::const_iterator> smatch;
-typedef match_results<wstring::const_iterator> wsmatch;
-
template <class _BidirectionalIterator, class _Allocator>
bool
operator==(const match_results<_BidirectionalIterator, _Allocator>& __x,
@@ -6182,7 +6201,21 @@
template <class _BidirectionalIterator,
class _CharT = typename iterator_traits<_BidirectionalIterator>::value_type,
class _Traits = regex_traits<_CharT> >
-class _LIBCPP_TEMPLATE_VIS regex_iterator
+ class _LIBCPP_TEMPLATE_VIS regex_iterator;
+
+typedef regex_iterator<const char*> cregex_iterator;
+typedef regex_iterator<const wchar_t*> wcregex_iterator;
+typedef regex_iterator<string::const_iterator> sregex_iterator;
+typedef regex_iterator<wstring::const_iterator> wsregex_iterator;
+
+template <class _BidirectionalIterator, class _CharT, class _Traits>
+class
+ _LIBCPP_TEMPLATE_VIS
+ _LIBCPP_PREFERRED_NAME(cregex_iterator)
+ _LIBCPP_PREFERRED_NAME(wcregex_iterator)
+ _LIBCPP_PREFERRED_NAME(sregex_iterator)
+ _LIBCPP_PREFERRED_NAME(wsregex_iterator)
+ regex_iterator
{
public:
typedef basic_regex<_CharT, _Traits> regex_type;
@@ -6291,17 +6324,26 @@
return *this;
}
-typedef regex_iterator<const char*> cregex_iterator;
-typedef regex_iterator<const wchar_t*> wcregex_iterator;
-typedef regex_iterator<string::const_iterator> sregex_iterator;
-typedef regex_iterator<wstring::const_iterator> wsregex_iterator;
-
// regex_token_iterator
template <class _BidirectionalIterator,
class _CharT = typename iterator_traits<_BidirectionalIterator>::value_type,
class _Traits = regex_traits<_CharT> >
-class _LIBCPP_TEMPLATE_VIS regex_token_iterator
+ class _LIBCPP_TEMPLATE_VIS regex_token_iterator;
+
+typedef regex_token_iterator<const char*> cregex_token_iterator;
+typedef regex_token_iterator<const wchar_t*> wcregex_token_iterator;
+typedef regex_token_iterator<string::const_iterator> sregex_token_iterator;
+typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
+
+template <class _BidirectionalIterator, class _CharT, class _Traits>
+class
+ _LIBCPP_TEMPLATE_VIS
+ _LIBCPP_PREFERRED_NAME(cregex_token_iterator)
+ _LIBCPP_PREFERRED_NAME(wcregex_token_iterator)
+ _LIBCPP_PREFERRED_NAME(sregex_token_iterator)
+ _LIBCPP_PREFERRED_NAME(wsregex_token_iterator)
+ regex_token_iterator
{
public:
typedef basic_regex<_CharT, _Traits> regex_type;
@@ -6579,11 +6621,6 @@
return *this;
}
-typedef regex_token_iterator<const char*> cregex_token_iterator;
-typedef regex_token_iterator<const wchar_t*> wcregex_token_iterator;
-typedef regex_token_iterator<string::const_iterator> sregex_token_iterator;
-typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
-
// regex_replace
template <class _OutputIterator, class _BidirectionalIterator,
Index: libcxx/include/iosfwd
===================================================================
--- libcxx/include/iosfwd
+++ libcxx/include/iosfwd
@@ -185,6 +185,38 @@
typedef basic_ofstream<wchar_t> wofstream;
typedef basic_fstream<wchar_t> wfstream;
+#ifdef _LIBCPP_PREFERRED_NAME
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(ios) _LIBCPP_PREFERRED_NAME(wios) basic_ios;
+
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(streambuf) _LIBCPP_PREFERRED_NAME(wstreambuf) basic_streambuf;
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(istream) _LIBCPP_PREFERRED_NAME(wistream) basic_istream;
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(ostream) _LIBCPP_PREFERRED_NAME(wostream) basic_ostream;
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(iostream) _LIBCPP_PREFERRED_NAME(wiostream) basic_iostream;
+
+template <class _CharT, class _Traits, class _Allocator>
+ class _LIBCPP_PREFERRED_NAME(stringbuf) _LIBCPP_PREFERRED_NAME(wstringbuf) basic_stringbuf;
+template <class _CharT, class _Traits, class _Allocator>
+ class _LIBCPP_PREFERRED_NAME(istringstream) _LIBCPP_PREFERRED_NAME(wistringstream) basic_istringstream;
+template <class _CharT, class _Traits, class _Allocator>
+ class _LIBCPP_PREFERRED_NAME(ostringstream) _LIBCPP_PREFERRED_NAME(wostringstream) basic_ostringstream;
+template <class _CharT, class _Traits, class _Allocator>
+ class _LIBCPP_PREFERRED_NAME(stringstream) _LIBCPP_PREFERRED_NAME(wstringstream) basic_stringstream;
+
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(filebuf) _LIBCPP_PREFERRED_NAME(wfilebuf) basic_filebuf;
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(ifstream) _LIBCPP_PREFERRED_NAME(wifstream) basic_ifstream;
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(ofstream) _LIBCPP_PREFERRED_NAME(wofstream) basic_ofstream;
+template <class _CharT, class _Traits>
+ class _LIBCPP_PREFERRED_NAME(fstream) _LIBCPP_PREFERRED_NAME(wfstream) basic_fstream;
+#endif
+
template <class _State> class _LIBCPP_TEMPLATE_VIS fpos;
typedef fpos<mbstate_t> streampos;
typedef fpos<mbstate_t> wstreampos;
@@ -210,6 +242,10 @@
typedef basic_string<char, char_traits<char>, allocator<char> > string;
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring;
+#ifdef _LIBCPP_PREFERRED_NAME
+template <class _CharT, class _Traits, class _Allocator>
+ class _LIBCPP_PREFERRED_NAME(string) _LIBCPP_PREFERRED_NAME(wstring) basic_string;
+#endif
// Include other forward declarations here
template <class _Tp, class _Alloc = allocator<_Tp> >
Index: libcxx/include/__config
===================================================================
--- libcxx/include/__config
+++ libcxx/include/__config
@@ -1330,6 +1330,12 @@
#endif
#endif // !defined(_LIBCPP_NODEBUG_TYPE)
+#if __has_attribute(__preferred_name__)
+#define _LIBCPP_PREFERRED_NAME(x) __attribute__((__preferred_name__(x)))
+#else
+#define _LIBCPP_PREFERRED_NAME(x)
+#endif
+
#if defined(_LIBCPP_ABI_MICROSOFT) && \
(defined(_LIBCPP_COMPILER_MSVC) || __has_declspec_attribute(empty_bases))
# define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1149,8 +1149,9 @@
<< "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
OS << " ExprResult " << "Result = S.SubstExpr("
<< "A->get" << getUpperName() << "(), TemplateArgs);\n";
- OS << " tempInst" << getUpperName() << " = "
- << "Result.getAs<Expr>();\n";
+ OS << " if (Result.isInvalid())\n";
+ OS << " return nullptr;\n";
+ OS << " tempInst" << getUpperName() << " = Result.get();\n";
OS << " }\n";
}
@@ -1202,7 +1203,9 @@
<< "_end();\n";
OS << " for (; I != E; ++I, ++TI) {\n";
OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
- OS << " *TI = Result.getAs<Expr>();\n";
+ OS << " if (Result.isInvalid())\n";
+ OS << " return nullptr;\n";
+ OS << " *TI = Result.get();\n";
OS << " }\n";
OS << " }\n";
}
@@ -1273,8 +1276,16 @@
OS << " return false;\n";
}
+ void writeTemplateInstantiation(raw_ostream &OS) const override {
+ OS << " " << getType() << " tempInst" << getUpperName() << " =\n";
+ OS << " S.SubstType(A->get" << getUpperName() << "Loc(), "
+ << "TemplateArgs, A->getLoc(), A->getAttrName());\n";
+ OS << " if (!tempInst" << getUpperName() << ")\n";
+ OS << " return nullptr;\n";
+ }
+
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
- OS << "A->get" << getUpperName() << "Loc()";
+ OS << "tempInst" << getUpperName();
}
void writePCHWrite(raw_ostream &OS) const override {
Index: clang/test/SemaTemplate/attributes.cpp
===================================================================
--- clang/test/SemaTemplate/attributes.cpp
+++ clang/test/SemaTemplate/attributes.cpp
@@ -63,3 +63,67 @@
// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAR"
template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations();
void UseAnnotations() { HasAnnotations<int>(); }
+
+namespace preferred_name {
+ int x [[clang::preferred_name("frank")]]; // expected-error {{expected a type}}
+ int y [[clang::preferred_name(int)]]; // expected-warning {{'preferred_name' attribute only applies to class templates}}
+ struct [[clang::preferred_name(int)]] A; // expected-warning {{'preferred_name' attribute only applies to class templates}}
+ template<typename T> struct [[clang::preferred_name(int)]] B; // expected-error {{argument 'int' to 'preferred_name' attribute is not a typedef for a specialization of 'B'}}
+ template<typename T> struct C;
+ using X = C<int>; // expected-note {{'X' declared here}}
+ typedef C<float> Y;
+ using Z = const C<double>; // expected-note {{'Z' declared here}}
+ template<typename T> struct [[clang::preferred_name(C<int>)]] C; // expected-error {{argument 'C<int>' to 'preferred_name' attribute is not a typedef for a specialization of 'C'}}
+ template<typename T> struct [[clang::preferred_name(X), clang::preferred_name(Y)]] C;
+ template<typename T> struct [[clang::preferred_name(const X)]] C; // expected-error {{argument 'const preferred_name::X'}}
+ template<typename T> struct [[clang::preferred_name(Z)]] C; // expected-error {{argument 'preferred_name::Z' (aka 'const C<double>')}}
+ template<typename T> struct C {};
+
+ // CHECK: ClassTemplateDecl {{.*}} <line:[[@LINE-10]]:{{.*}} C
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
+ // CHECK: TemplateArgument type 'int'
+ // CHECK-NOT: PreferredNameAttr
+ // CHECK: PreferredNameAttr {{.*}} preferred_name::X
+ // CHECK-NOT: PreferredNameAttr
+ // CHECK: CXXRecordDecl
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
+ // CHECK: TemplateArgument type 'float'
+ // CHECK-NOT: PreferredNameAttr
+ // CHECK: PreferredNameAttr {{.*}} preferred_name::Y
+ // CHECK-NOT: PreferredNameAttr
+ // CHECK: CXXRecordDecl
+ // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
+ // CHECK: TemplateArgument type 'double'
+ // CHECK-NOT: PreferredNameAttr
+ // CHECK: CXXRecordDecl
+
+ // Check this doesn't cause us to instantiate the same attribute multiple times.
+ C<float> *cf1;
+ C<float> *cf2;
+
+ void f(C<int> a, C<float> b, C<double> c) {
+ auto p = a;
+ auto q = b;
+ auto r = c;
+ p.f(); // expected-error {{no member named 'f' in 'preferred_name::X'}}
+ q.f(); // expected-error {{no member named 'f' in 'preferred_name::Y'}}
+ r.f(); // expected-error {{no member named 'f' in 'preferred_name::C<double>'}}
+ }
+
+ template<typename T> struct D;
+ using DInt = D<int>;
+ template<typename T> struct __attribute__((__preferred_name__(DInt))) D {};
+ template struct D<int>;
+ int use_dint = D<int>().get(); // expected-error {{no member named 'get' in 'preferred_name::DInt'}}
+
+ template<typename T> struct MemberTemplate {
+ template<typename U> struct Iter;
+ using iterator = Iter<T>;
+ using const_iterator = Iter<const T>;
+ template<typename U>
+ struct [[clang::preferred_name(iterator),
+ clang::preferred_name(const_iterator)]] Iter {};
+ };
+ auto it = MemberTemplate<int>::Iter<const int>();
+ int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
+}
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -548,12 +548,43 @@
S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
}
+/// Determine whether the attribute A might be relevent to the declaration D.
+/// If not, we can skip instantiating it. The attribute may or may not have
+/// been instantiated yet.
+static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
+ // 'preferred_name' is only relevant to the matching specialization of the
+ // template.
+ if (const auto *PNA = dyn_cast<PreferredNameAttr>(A)) {
+ QualType T = PNA->getTypedefType();
+ const auto *RD = cast<CXXRecordDecl>(D);
+ if (!T->isDependentType() && !RD->isDependentContext() &&
+ !declaresSameEntity(T->getAsCXXRecordDecl(), RD)) {
+ T->getAsCXXRecordDecl()->dump();
+ RD->dump();
+ return false;
+ }
+ for (const auto *ExistingPNA : D->specific_attrs<PreferredNameAttr>())
+ if (S.Context.hasSameType(ExistingPNA->getTypedefType(),
+ PNA->getTypedefType()))
+ return false;
+ return true;
+ }
+
+ return true;
+}
+
void Sema::InstantiateAttrsForDecl(
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
Decl *New, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(New)) {
+ // FIXME: This function is called multiple times for the same template
+ // specialization. We should only instantiate attributes that were added
+ // since the previous instantiation.
for (const auto *TmplAttr : Tmpl->attrs()) {
+ if (!isRelevantAttr(*this, New, TmplAttr))
+ continue;
+
// FIXME: If any of the special case versions from InstantiateAttrs become
// applicable to template declaration, we'll need to add them here.
CXXThisScopeRAII ThisScope(
@@ -562,7 +593,7 @@
Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(
TmplAttr, Context, *this, TemplateArgs);
- if (NewAttr)
+ if (NewAttr && isRelevantAttr(*this, New, NewAttr))
New->addAttr(NewAttr);
}
}
@@ -587,6 +618,9 @@
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
for (const auto *TmplAttr : Tmpl->attrs()) {
+ if (!isRelevantAttr(*this, New, TmplAttr))
+ continue;
+
// FIXME: This should be generalized to more than just the AlignedAttr.
const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
if (Aligned && Aligned->isAlignmentDependent()) {
@@ -709,7 +743,7 @@
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
- if (NewAttr)
+ if (NewAttr && isRelevantAttr(*this, New, TmplAttr))
New->addAttr(NewAttr);
}
}
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3792,11 +3792,15 @@
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
}
- if (Decl->getSpecializationKind() == TSK_Undeclared) {
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(Converted);
- InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(),
- Decl);
+ if (Decl->getSpecializationKind() == TSK_Undeclared &&
+ ClassTemplate->getTemplatedDecl()->hasAttrs()) {
+ InstantiatingTemplate Inst(*this, TemplateLoc, Decl);
+ if (!Inst.isInvalid()) {
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(Converted);
+ InstantiateAttrsForDecl(TemplateArgLists,
+ ClassTemplate->getTemplatedDecl(), Decl);
+ }
}
// Diagnose uses of this specialization.
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -1380,6 +1380,43 @@
S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
}
+static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) {
+ auto *RD = cast<CXXRecordDecl>(D);
+ ClassTemplateDecl *CTD = RD->getDescribedClassTemplate();
+ assert(CTD && "attribute does not appertain to this declaration");
+
+ ParsedType PT = AL.getTypeArg();
+ TypeSourceInfo *TSI = nullptr;
+ QualType T = S.GetTypeFromParser(PT, &TSI);
+ if (!TSI)
+ TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc());
+
+ if (!T.hasQualifiers() && T->getAs<TypedefType>()) {
+ // Find the template name, if this type names a template specialization.
+ const TemplateDecl *Template = nullptr;
+ if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ T->getAsCXXRecordDecl())) {
+ Template = CTSD->getSpecializedTemplate();
+ } else if (const auto *TST = T->getAs<TemplateSpecializationType>()) {
+ while (TST && TST->isTypeAlias())
+ TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
+ if (TST)
+ Template = TST->getTemplateName().getAsTemplateDecl();
+ }
+
+ if (Template && declaresSameEntity(Template, CTD)) {
+ D->addAttr(::new (S.Context) PreferredNameAttr(S.Context, AL, TSI));
+ return;
+ }
+ }
+
+ S.Diag(AL.getLoc(), diag::err_attribute_preferred_name_arg_invalid)
+ << T << CTD;
+ if (const auto *TT = T->getAs<TypedefType>())
+ S.Diag(TT->getDecl()->getLocation(), diag::note_entity_declared_at)
+ << TT->getDecl();
+}
+
static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) {
// The IBOutlet/IBOutletCollection attributes only apply to instance
// variables or properties of Objective-C classes. The outlet must also
@@ -7704,6 +7741,9 @@
case ParsedAttr::AT_Packed:
handlePackedAttr(S, D, AL);
break;
+ case ParsedAttr::AT_PreferredName:
+ handlePreferredName(S, D, AL);
+ break;
case ParsedAttr::AT_Section:
handleSectionAttr(S, D, AL);
break;
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -10,8 +10,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -19,6 +19,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
@@ -1348,6 +1349,14 @@
}
void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
+ // Print the preferred name if we have one for this type.
+ for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) {
+ if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
+ T->getDecl()))
+ return printTypeSpec(
+ PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
+ }
+
printTag(T->getDecl(), OS);
}
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3937,6 +3937,9 @@
"protocol is declared here">;
def note_protocol_decl_undefined : Note<
"protocol %0 has no definition">;
+def err_attribute_preferred_name_arg_invalid : Error<
+ "argument %0 to 'preferred_name' attribute is not a typedef for "
+ "a specialization of %1">;
// objc_designated_initializer attribute diagnostics.
def warn_objc_designated_init_missing_super_call : Warning<
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -4387,6 +4387,30 @@
}];
}
+def PreferredNameDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{
+The ``preferred_name`` attribute can be applied to a class template, and
+specifies a preferred way of naming a specialization of the template. The
+preferred name will be used whenever the corresponding template specialization
+would otherwise be printed in a diagnostic or similar context.
+
+The preferred name must be a typedef or type alias declaration that refers to a
+specialization of the class template (not including any type qualifiers). In
+general this requires the template to be declared at least twice. For example:
+
+.. code-block:: c++
+
+ template<typename T> struct basic_string;
+ using string = basic_string<char>;
+ using wstring = basic_string<wchar_t>;
+ template<typename T> struct [[clang::preferred_name(string),
+ clang::preferred_name(wstring)]] basic_string {
+ // ...
+ };
+ }];
+}
+
def PreserveMostDocs : Documentation {
let Category = DocCatCallingConvs;
let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -126,6 +126,9 @@
FunctionDecl::TK_FunctionTemplate}],
"function templates">;
+def ClassTmpl : SubsetSubject<CXXRecord, [{S->getDescribedClassTemplate()}],
+ "class templates">;
+
// FIXME: this hack is needed because DeclNodes.td defines the base Decl node
// type to be a class, not a definition. This makes it impossible to create an
// attribute subject which accepts a Decl. Normally, this is not a problem,
@@ -2360,6 +2363,16 @@
let Documentation = [Undocumented];
}
+def PreferredName : InheritableAttr {
+ let Spellings = [Clang<"preferred_name", /*AllowInC*/0>];
+ let Subjects = SubjectList<[ClassTmpl]>;
+ let Args = [TypeArgument<"TypedefType">];
+ let Documentation = [PreferredNameDocs];
+ let InheritEvenIfAlreadyPresent = 1;
+ let MeaningfulToClassTemplateDefinition = 1;
+ let TemplateDependent = 1;
+}
+
def PreserveMost : DeclOrTypeAttr {
let Spellings = [Clang<"preserve_most">];
let Documentation = [PreserveMostDocs];
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits