tra created this revision. tra added reviewers: rsmith, arphaman. Herald added a subscriber: bixia. tra requested review of this revision. Herald added a project: clang.
The original intent of enforcing exact match between `apply_to` and the attribute's was to `ensure that the user will know what declarations receive the attribute. If the compiler changes the set of allowed attributes in the future`. https://reviews.llvm.org/D30009?id=88764#inline-260744 However, the exact match, as implemented now, is too conservative. E.g. it does not allow using `apply_to=variables(is_global)` with an attribute which has `SubjectList<[Var]>`. Applying an attribute to a subset of the allowed subjects should also be allowed. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D100136 Files: clang/lib/Sema/SemaAttr.cpp clang/test/Parser/pragma-attribute.cpp Index: clang/test/Parser/pragma-attribute.cpp =================================================================== --- clang/test/Parser/pragma-attribute.cpp +++ clang/test/Parser/pragma-attribute.cpp @@ -195,3 +195,12 @@ #pragma clang attribute pop #pragma clang attribute push([[clang::uninitialized]], apply_to = any(variable(is_parameter), variable(unless(is_parameter)))) // expected-error {{attribute 'uninitialized' can't be applied to 'variable(is_parameter)', and 'variable(unless(is_parameter))'}} #pragma clang attribute pop +// We're allowed to apply attributes to subsets of allowed subjects. +#pragma clang attribute push([[clang::no_destroy]], apply_to = variable) +#pragma clang attribute pop +#pragma clang attribute push([[clang::no_destroy]], apply_to = variable(is_thread_local)) +#pragma clang attribute pop +#pragma clang attribute push([[clang::no_destroy]], apply_to = variable(is_global)) +#pragma clang attribute pop +#pragma clang attribute push([[clang::no_destroy]], apply_to = any(variable(is_parameter), variable(unless(is_parameter)))) +#pragma clang attribute pop Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -875,12 +875,33 @@ } Rules.clear(); } else { - for (const auto &Rule : StrictSubjectMatchRuleSet) { - if (Rules.erase(Rule.first)) { + // Each rule in Rules must be a strict subset of the attribute's + // SubjectMatch rules. I.e. we're allowed to use + // `apply_to=variables(is_global)` on an attrubute with SubjectList<[Var]>, + // but should not allow `apply_to=variables` on an attribute which has + // `SubjectList<[GlobalVar]>`. + for (const auto &StrictRule : StrictSubjectMatchRuleSet) { + // First, check for exact match. + if (Rules.erase(StrictRule.first)) { // Add the rule to the set of attribute receivers only if it's supported // in the current language mode. - if (Rule.second) - SubjectMatchRules.push_back(Rule.first); + if (StrictRule.second) + SubjectMatchRules.push_back(StrictRule.first); + } + } + // Check remaining rules for subset matches. + auto RulesToCheck = Rules; + for (const auto &Rule : RulesToCheck) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + if (auto ParentRule = getParentAttrMatcherRule(MatchRule)) { + if (llvm::any_of(StrictSubjectMatchRuleSet, + [ParentRule](const auto &StrictRule) { + return StrictRule.first == *ParentRule && + StrictRule.second; // IsEnabled + })) { + SubjectMatchRules.push_back(MatchRule); + Rules.erase(MatchRule); + } } } }
Index: clang/test/Parser/pragma-attribute.cpp =================================================================== --- clang/test/Parser/pragma-attribute.cpp +++ clang/test/Parser/pragma-attribute.cpp @@ -195,3 +195,12 @@ #pragma clang attribute pop #pragma clang attribute push([[clang::uninitialized]], apply_to = any(variable(is_parameter), variable(unless(is_parameter)))) // expected-error {{attribute 'uninitialized' can't be applied to 'variable(is_parameter)', and 'variable(unless(is_parameter))'}} #pragma clang attribute pop +// We're allowed to apply attributes to subsets of allowed subjects. +#pragma clang attribute push([[clang::no_destroy]], apply_to = variable) +#pragma clang attribute pop +#pragma clang attribute push([[clang::no_destroy]], apply_to = variable(is_thread_local)) +#pragma clang attribute pop +#pragma clang attribute push([[clang::no_destroy]], apply_to = variable(is_global)) +#pragma clang attribute pop +#pragma clang attribute push([[clang::no_destroy]], apply_to = any(variable(is_parameter), variable(unless(is_parameter)))) +#pragma clang attribute pop Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -875,12 +875,33 @@ } Rules.clear(); } else { - for (const auto &Rule : StrictSubjectMatchRuleSet) { - if (Rules.erase(Rule.first)) { + // Each rule in Rules must be a strict subset of the attribute's + // SubjectMatch rules. I.e. we're allowed to use + // `apply_to=variables(is_global)` on an attrubute with SubjectList<[Var]>, + // but should not allow `apply_to=variables` on an attribute which has + // `SubjectList<[GlobalVar]>`. + for (const auto &StrictRule : StrictSubjectMatchRuleSet) { + // First, check for exact match. + if (Rules.erase(StrictRule.first)) { // Add the rule to the set of attribute receivers only if it's supported // in the current language mode. - if (Rule.second) - SubjectMatchRules.push_back(Rule.first); + if (StrictRule.second) + SubjectMatchRules.push_back(StrictRule.first); + } + } + // Check remaining rules for subset matches. + auto RulesToCheck = Rules; + for (const auto &Rule : RulesToCheck) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + if (auto ParentRule = getParentAttrMatcherRule(MatchRule)) { + if (llvm::any_of(StrictSubjectMatchRuleSet, + [ParentRule](const auto &StrictRule) { + return StrictRule.first == *ParentRule && + StrictRule.second; // IsEnabled + })) { + SubjectMatchRules.push_back(MatchRule); + Rules.erase(MatchRule); + } } } }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits