Current version there is a fix-it for
template <class> constexpr int x = 0; template <> constexpr int x<int>; // fix-it here
but it will cause
template <> constexpr int x = 0<int>;
Differential D139705
[clang] fix zero-initialization fix-it for variable template v1nh1shungry on Dec 9 2022, 4:01 AM. Authored by
Details Current version there is a fix-it for template <class> constexpr int x = 0; template <> constexpr int x<int>; // fix-it here but it will cause template <> constexpr int x = 0<int>;
Diff Detail
Event Timeline
Comment Actions As far as teh fix itself, I think this is fine. BUT i think there is value in waiting for Aaron to see if there is a deeper issue here.
Comment Actions Thanks for the reply! I'll raise a GitHub issue.
Can I post your reply there? I think it will help.
Then I think this patch is ready for a review. Comment Actions Yes, absolutely!
Changes LGTM though you should add a release note to tell users about the fix. Thank you! Comment Actions Thank you for reviewing! I have opened an issue on GitHub: https://github.com/llvm/llvm-project/issues/59935. Hope my description is appropriate.
Comment Actions I'm happy to, what name and email address would you like used for patch attribution? Alternatively, it seems that you've had a few patches accepted in the project, so you could apply for commit access yourself if you'd like: https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access Comment Actions
I'd like "v1nh1shungry" and "v1nh1shungry@outlook.com". Thank you!
Cool! I'll give it a try. Thanks! Comment Actions Sorry to disturb you again! It's been a week since I sent an email to Chris, and I have received no reply. Maybe my request was refused. It'd be great to land this and https://reviews.llvm.org/D140838 before the 16 release, right? If so, could you please help me commit them? I'd like "v1nh1shungry <v1nh1shungry@outlook.com>". Thank you so much! Comment Actions I doubt your request was refused, my guess is that Chris is busy at the moment (CC @lattner). I'm happy to land this for you though! Comment Actions I'm pretty sure I'm on top of commit access requests now, plz let me know if I missed you or something! Could be spam filter or who knows what Comment Actions I sent an email from <v1nh1shungry@outlook.com> to I can resend the email. Or maybe we can deal with it here? If so, my GitHub username is v1nh1shungry (https://github.com/v1nh1shungry). Thank you so much! Comment Actions As a downstream, we have concerns with this change. From what I saw it breaks the behavior of the fix-it that wants to remove the whole variable definition (including the initializer). For example, I have unused, that I want to remove variable x and unnecessary explicit specialization temp<double>: template<typename T> T temp = 1; int x = 10; template<> double temp<double> = 1; Previously, this could be handled (in case of single variable declaration) by simply removing up the var->getSourceRange() with succeeding coma. However, after the change, such code does not work, and in general if getSourceRange() is used on VarDecl (or even Decl), special consideration needs to be taken for the situation when VarDecl refers to variable template specialization. As an alternative, I would suggest introducing an additional function to VarDecl (which could be moved up in the hierarchy), that would report a source range that corresponds to declarator-id, i.e. for template variable it would include template arguments. Comment Actions Hmm... I'm being a little dense here I guess, I don't understand what you mean? Does this result in one of our fixits being wrong here? With the old range, wouldn't it have left the <double> in that case, and now is removing it? Or what am I missing? Comment Actions For both x and temp<double>, prior to the change the getSourceRange() on the VarDecl that represents them includes an initializer (they end just before ;). But now for the variable template specialization, we end up just after template arguments. This means that fixit/report that previously covered the whole definition, will now not include an initializer. template<typename T> T temp = 1; // v getSourceRange() ends on this token before and after the change int x = 10; // v getSourceRange() ends on this token prior to the change, consistently with normal variables template<> double temp<double> = 1; // ^ getSourceRange() ends on this token after the change, making it inconsistent Comment Actions Thank you for the further explanation, that clarified the concern for me as well. I think I agree with you -- we used to cover the full source range for the AST node, and now we only cover part of it because we're missing the initializer. We want getSourceRange() to cover the full range of text for the node, so we should have a different function to access the more limited range. @v1nh1shungry is this something you'd feel comfortable fixing up? Comment Actions Since the motivation for this patch here was "make sure we're pointing to the 'end' so we can suggest an init fixit", perhaps this SHOULD be changed to the 'end' still, but just fix the case where the initializer was omitted. So /// What USED to happen: template<> double temp<double> = 1; //End is here: ^ template<> double temp<double>; //End is here: ^ //What is happening now: template<> double temp<double> = 1; //End is here: ^ template<> double temp<double>; //End is here: ^ // What I think we want: template<> double temp<double> = 1; //End is here: ^ template<> double temp<double>; //End is here: ^ Right? So this isn't so much as a separate function, its just to make sure we get the 'source range' to include 'everything', including the initializer, if present. Comment Actions
Indeed, this would address our concern, and allow properly inserting initializer. This would build down to repeating the condition from here: https://github.com/llvm/llvm-project/blob/bbe1394c9602ab9a939d9b17199d5f538cac9d0c/clang/lib/AST/Decl.cpp#L1207. I was suggesting adding an additional function, as it would cover additional use cases like replacing or removing the initializer, and then VarDecl::getSourceRange could be defined as: SourceRange VarDecl::getSourceRange() const { if (const Expr *Init = getInit()) { SourceLocation InitEnd = Init->getEndLoc(); // If Init is implicit, ignore its source range and fallback on // DeclaratorDecl::getSourceRange() to handle postfix elements. if (InitEnd.isValid() && InitEnd != getLocation()) return SourceRange(getOuterLocStart(), InitEnd); } return getDeclatorRange(); } Comment Actions That would make sense to me. Feel free to submit a patch (assuming @v1nh1shungry doesn't respond/get to it first). Comment Actions Thank you for the suggestion! This makes sense to me too. But I'm sorry for being busy recently. Please feel free to submit a patch. Thank you! Comment Actions
I https://reviews.llvm.org/D146733 I have submitted a smaller patch, that addresses the regression and the concern. Unfortunately, at this time I am not able to commit to the introduction of the additional method, and its proper handling for AST nodes. Comment Actions While creating a test for the fix, I noticed the getSourceRange behavior is not stable after the serialization, as illustrated here: https://reviews.llvm.org/D146784 |
I'd like to see some additional test coverage for more complicated declarators: