-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang] Infer lifetime_capture_by for STL containers #117122
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 1 commit
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 |
|---|---|---|
|
|
@@ -268,6 +268,40 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) { | |
| } | ||
| } | ||
|
|
||
| static bool IsPointerLikeType(QualType QT) { | ||
usx95 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| QT = QT.getNonReferenceType(); | ||
| if (QT->isPointerType()) | ||
| return true; | ||
| auto *RD = QT->getAsCXXRecordDecl(); | ||
| if (!RD) | ||
| return false; | ||
| RD = RD->getCanonicalDecl(); | ||
| if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) | ||
| RD = CTSD->getSpecializedTemplate()->getTemplatedDecl(); | ||
|
Collaborator
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’s unclear to me why this case needs to be handled separately, and we already have one in
Contributor
Author
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. We fail to detect pointer types which are templates: template <class T> struct [[gsl::Pointer()]] ViewTemplate {};
std::vector<ViewTemplate<int>> templated_views;template<typename T>
struct [[gsl::Pointer]] Span {
Span(const std::vector<T> &V);
};
void use() {
std::vector<Span<int>> spans;
spans.push_back(std::vector<int>{1, 2, 3}); // warning.
}
Contributor
Author
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. Maybe a better fix would be to propagate this annotation to the template specialization in clang.
Collaborator
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. Thanks for the example. I think I understand what’s happening here. The primary template Span is annotated with the gsl::Pointer attribute, so all its specializations should inherit this attribute. However, in this example, at the point where we infer the I think the following case would work without this special handling. I don’t have a better suggestion for addressing this issue directly. However, I think we should have a comment explaining it. (Should we do the same thing for the one in
Contributor
Author
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.
That said, your example still doesn't work show the warning with the lines removed: if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
Collaborator
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. hmm, this is strange. I tested it locally, it works for me.
Contributor
Author
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. Hmm. I can reproduce with But I think you are right. I also suspected that we are just inspecting the template spec decl earlier than expected. |
||
| return RD->hasAttr<PointerAttr>(); | ||
| } | ||
|
|
||
| void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { | ||
| if (!FD) | ||
| return; | ||
| auto *MD = dyn_cast<CXXMethodDecl>(FD); | ||
| if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace()) | ||
| return; | ||
| static const llvm::StringSet<> CapturingMethods{"insert", "push", | ||
usx95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "push_front", "push_back"}; | ||
| if (!CapturingMethods.contains(MD->getName())) | ||
| return; | ||
| for (ParmVarDecl *PVD : MD->parameters()) { | ||
| if (PVD->hasAttr<LifetimeCaptureByAttr>()) | ||
| return; | ||
|
Collaborator
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. Is return intentional here? Do we want an explicit attr to turn off the inference for the rest of the params? If that is the case, I think we want to turn off the inference for the params before the explicit attr as well, not just after.
Contributor
Author
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, this was intentional. Good catch. Disabled if any of the parameters is explicitly annotated. |
||
| if (IsPointerLikeType(PVD->getType())) { | ||
| int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; | ||
| PVD->addAttr( | ||
| LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) { | ||
| static const llvm::StringSet<> Nullable{ | ||
| "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr", | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.