-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang] Add [[clang::no_specializations]] #101469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
82ab798
9d1b83b
328874b
dce818f
919835c
edc1290
003983f
510784d
5dd5dd4
87ae233
38cad13
95868ea
eb4fcfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1212,6 +1212,14 @@ static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) { | |
<< TT->getDecl(); | ||
} | ||
|
||
static void handleNoSpecializations(Sema &S, Decl *D, const ParsedAttr &AL) { | ||
StringRef Message; | ||
if (AL.getNumArgs() != 0) | ||
S.checkStringLiteralArgumentAttr(AL, 0, Message); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. static analysis flags this b/c you are not checking the return value of Please confirm the intent and please fix to check the return value or please modify to purposely ignore it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not 100% sure what the correct thing to do is. I don't think there's harm in adding the attribute without a string if the arguments are incorrect, since they don't affect what the attribute does in a significant way. OTOH there isn't that much benefit in adding it, since the program is ill-formed anyways. @AaronBallman any thoughts on this? P.S. why isn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Pretty sure this function, or its origin predate I don't see any good reason to change the code here, I think the SA tool isn't really adding value here, and I don't see anything I'd change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It stands out as completely inconsistent with the rest of the file, literally everywhere else it is checked and they return early. I am guessing if we return early here we should just get the proper diagnostic, right? Is this case somehow different from all the two dozen or so other uses? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it is inconsistent, but not really an issue. About 1/2 the uses have some additional processing that needs to happen, so the early return is sensible, though perhaps they could better reflect the code in that case. But the other 1/2 could very well have their return removed with no negative effects (and likely, an improvement, as the error-AST would better reflect the syntax). The only reason NOT to do a mass-changeover is that we're not sure which were written in a way to not properly expect an empty string here in codegen/etc. That said, a bug report marked 'good-first-issue' for someone to go through the uses and ensure we are tolerant of them would be a good idea. @shafik: mind filing one? |
||
D->getDescribedTemplate()->addAttr( | ||
NoSpecializationsAttr::Create(S.Context, Message, AL)); | ||
} | ||
|
||
bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { | ||
if (T->isDependentType()) | ||
return true; | ||
|
@@ -6913,6 +6921,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, | |
case ParsedAttr::AT_PreferredName: | ||
handlePreferredName(S, D, AL); | ||
break; | ||
case ParsedAttr::AT_NoSpecializations: | ||
handleNoSpecializations(S, D, AL); | ||
break; | ||
case ParsedAttr::AT_Section: | ||
handleSectionAttr(S, D, AL); | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// RUN: %clang_cc1 %s -verify | ||
|
||
#if !__has_cpp_attribute(clang::no_specializations) | ||
# error | ||
#endif | ||
|
||
struct [[clang::no_specializations]] S {}; // expected-warning {{'no_specializations' attribute only applies to class templates, function templates, and variable templates}} | ||
|
||
template <class T, class U> | ||
struct [[clang::no_specializations]] is_same { // expected-note 2 {{marked 'no_specializations' here}} | ||
static constexpr bool value = __is_same(T, U); | ||
}; | ||
|
||
template <class T> | ||
using alias [[clang::no_specializations]] = T; // expected-warning {{'no_specializations' attribute only applies to class templates, function templates, and variable templates}} | ||
|
||
template <> | ||
struct is_same<int, char> {}; // expected-error {{'is_same' cannot be specialized}} | ||
|
||
template <class> | ||
struct Template {}; | ||
|
||
template <class T> | ||
struct is_same<Template<T>, Template <T>> {}; // expected-error {{'is_same' cannot be specialized}} | ||
|
||
bool test_instantiation1 = is_same<int, int>::value; | ||
|
||
template <class T, class U> | ||
[[clang::no_specializations]] inline constexpr bool is_same_v = __is_same(T, U); // expected-note 2 {{marked 'no_specializations' here}} | ||
|
||
template <> | ||
inline constexpr bool is_same_v<int, char> = false; // expected-error {{'is_same_v' cannot be specialized}} | ||
|
||
template <class T> | ||
inline constexpr bool is_same_v<Template <T>, Template <T>> = true; // expected-error {{'is_same_v' cannot be specialized}} | ||
|
||
bool test_instantiation2 = is_same_v<int, int>; | ||
|
||
template <class T> | ||
struct [[clang::no_specializations("specializing type traits results in undefined behaviour")]] is_trivial { // expected-note {{marked 'no_specializations' here}} | ||
static constexpr bool value = __is_trivial(T); | ||
}; | ||
|
||
template <> | ||
struct is_trivial<int> {}; // expected-error {{'is_trivial' cannot be specialized: specializing type traits results in undefined behaviour}} | ||
|
||
template <class T> | ||
[[clang::no_specializations("specializing type traits results in undefined behaviour")]] inline constexpr bool is_trivial_v = __is_trivial(T); // expected-note {{marked 'no_specializations' here}} | ||
|
||
template <> | ||
inline constexpr bool is_trivial_v<int> = false; // expected-error {{'is_trivial_v' cannot be specialized: specializing type traits results in undefined behaviour}} | ||
|
||
template <class T> | ||
struct Partial {}; | ||
|
||
template <class T> | ||
struct [[clang::no_specializations]] Partial<Template <T>> {}; // expected-warning {{'no_specializations' attribute only applies to class templates, function templates, and variable templates}} | ||
|
||
template <class T> | ||
[[clang::no_specializations]] void func(); // expected-note {{marked 'no_specializations' here}} | ||
|
||
template <> void func<int>(); // expected-error {{'func' cannot be specialized}} |
Uh oh!
There was an error while loading. Please reload this page.