-
Notifications
You must be signed in to change notification settings - Fork 340
[BoundsSafety] Delay processing of bounds attrs in templates #9929
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
[BoundsSafety] Delay processing of bounds attrs in templates #9929
Conversation
@@ -3485,6 +3485,9 @@ namespace clang { | |||
|
|||
void DynamicCountPointerAssignmentAnalysis::run() { | |||
AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, dcl); | |||
if (isa<TemplateDecl>(dcl)) // delay processing until template has been | |||
// instantiated | |||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does it work? Will DynamicCountPointerAssignmentAnalysis::run
be called again when dcl
is instantiated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, a new function decl will be created for the instantiated version and all the normal analyses will be run over it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this sufficient? We could have dependent expressions when the declaration itself is not templated:
- Non-templated method of a templated struct referencing the template argument
- Lambda inside a templated function referencing the template argument
- Method of a non-templated struct nested inside a templated struct referencing the outer struct's template argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to an isTemplated
call instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dumb question: what's the difference between using isTemplated
and isDependentContext()
to rule out templates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isTemplated
covers some extra cases:
bool Decl::isTemplated() const {
// A declaration is templated if it is a template or a template pattern, or
// is within (lexcially for a friend or local function declaration,
// semantically otherwise) a dependent context.
if (auto *AsDC = dyn_cast<DeclContext>(this))
return AsDC->isDependentContext();
auto *DC = getFriendObjectKind() || isLocalExternDecl()
? getLexicalDeclContext() : getDeclContext();
return DC->isDependentContext() || isTemplateDecl() ||
getDescribedTemplateParams();
}
CC @ziqingluo-90 since we were discussing templates recently. |
@swift-ci please test |
@swift-ci please test llvm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure non-templated entities nested in templated entities are correctly handled, the very least we should have some tests for that. Added some examples of such cases inline.
@@ -3485,6 +3485,9 @@ namespace clang { | |||
|
|||
void DynamicCountPointerAssignmentAnalysis::run() { | |||
AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, dcl); | |||
if (isa<TemplateDecl>(dcl)) // delay processing until template has been | |||
// instantiated | |||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this sufficient? We could have dependent expressions when the declaration itself is not templated:
- Non-templated method of a templated struct referencing the template argument
- Lambda inside a templated function referencing the template argument
- Method of a non-templated struct nested inside a templated struct referencing the outer struct's template argument
clang/lib/Sema/SemaDeclAttr.cpp
Outdated
static void handlePtrCountedByEndedByAttr(Sema &S, Decl *D, | ||
const ParsedAttr &AL) { | ||
unsigned Level; | ||
if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(1), Level)) | ||
return; | ||
|
||
if (D->getDescribedTemplate() || S.CurContext->isDependentContext()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here, wondering if this is sufficient for non-templated entities nested in templates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also replaced with a call to isTemplated
427922f
to
9858ef7
Compare
@swift-ci please test llvm |
@swift-ci please smoke test |
Just curious: will you allow
|
This is currently ignored. I think it's related to how these attributes are completely ignored in casts, even C-style casts. I don't have any plans to fix this right now, but I do think that it would be good to get there eventually. |
@swift-ci please test llvm |
@swift-ci please smoke test |
Dynamic bounds attributes do not handle value dependent arguments. To enable wider interop with C++ code bases we delay the processing of these attributes inside templated contexts. Instead we apply the new type while instantiating the function. One issue with this approach is that instantiation happens after parsing is finished, and the Scope information we use to prevent attributes from referring to arguments from outer scopes is only available during parsing. These diagnostics were emitted at the end of the type processing. In templated contexts we instead perform that analysis during parsing, and delay the rest of the processing. To avoid churn in unrelated tests the rest of the attributes keep their processing as is, until we've investigated what impact hoisting it would have on the user experience.
This analysis is now done after inserting BoundsCheckExpr, so we need to peek through them to emit these warnings where we previously only had a BoundsSafetyPointerCast.
6cabde8
to
8510657
Compare
@swift-ci please test |
windows failure seems unrelated |
@swift-ci please test llvm |
This is a cherry-pick of change that was landed to `stable/20240723` (swiftlang#9929) but not landed on the `next` branch. Aside from resolving merge conflicts it was also necessary to modify the `clang/test/BoundsSafety/(AST|Sema)/value-dependence.cpp` tests because they fail to work when the new bounds checks are enabled (rdar://150044760). To workaround that the test has been made to disable the new `return_size` bounds check when `-fbounds-safety` is enabled with C++. --- * [BoundsSafety] Delay processing of bounds attrs in templates Dynamic bounds attributes do not handle value dependent arguments. To enable wider interop with C++ code bases we delay the processing of these attributes inside templated contexts. Instead we apply the new type while instantiating the function. One issue with this approach is that instantiation happens after parsing is finished, and the Scope information we use to prevent attributes from referring to arguments from outer scopes is only available during parsing. These diagnostics were emitted at the end of the type processing. In templated contexts we instead perform that analysis during parsing, and delay the rest of the processing. To avoid churn in unrelated tests the rest of the attributes keep their processing as is, until we've investigated what impact hoisting it would have on the user experience. Conflicts: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-count-attributed-pointer-argument.cpp rdar://150694971 (cherry picked from commit c87bc75)
This is a cherry-pick of change that was landed to `stable/20240723` (#9929) but not landed on the `next` branch. Aside from resolving merge conflicts it was also necessary to modify the `clang/test/BoundsSafety/(AST|Sema)/value-dependence.cpp` tests because they fail to work when the new bounds checks are enabled (rdar://150044760). To workaround that the test has been made to disable the new `return_size` bounds check when `-fbounds-safety` is enabled with C++. --- * [BoundsSafety] Delay processing of bounds attrs in templates Dynamic bounds attributes do not handle value dependent arguments. To enable wider interop with C++ code bases we delay the processing of these attributes inside templated contexts. Instead we apply the new type while instantiating the function. One issue with this approach is that instantiation happens after parsing is finished, and the Scope information we use to prevent attributes from referring to arguments from outer scopes is only available during parsing. These diagnostics were emitted at the end of the type processing. In templated contexts we instead perform that analysis during parsing, and delay the rest of the processing. To avoid churn in unrelated tests the rest of the attributes keep their processing as is, until we've investigated what impact hoisting it would have on the user experience. Conflicts: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-count-attributed-pointer-argument.cpp rdar://150694971 (cherry picked from commit c87bc75)
Dynamic bounds attributes do not handle value dependent arguments. To enable wider interop with C++ code bases we delay the processing of these attributes inside templated contexts. Instead we apply the new type while instantiating the function.
One issue with this approach is that instantiation happens after parsing is finished, and the Scope information we use to prevent attributes from referring to arguments from outer scopes is only available during parsing. These diagnostics were emitted at the end of the type processing. In templated contexts we instead perform that analysis during parsing, and delay the rest of the processing. To avoid churn in unrelated tests the rest of the attributes keep their processing as is, until we've investigated what impact hoisting it would have on the user experience.