-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Fix crash with modules and constexpr destructor #69076
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
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-modules Author: Jonas Hahnfeld (hahnjo) ChangesCloses #68702 Full diff: https://github.com/llvm/llvm-project/pull/69076.diff 2 Files Affected:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e5539dedec02a4b..a97e7bd8140890e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15604,10 +15604,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
LValue LVal;
LVal.set(VD);
- if (!EvaluateInPlace(Value, Info, LVal, this,
- /*AllowNonLiteralTypes=*/true) ||
- EStatus.HasSideEffects)
- return false;
+ {
+ FullExpressionRAII Scope(Info);
+ if (!EvaluateInPlace(Value, Info, LVal, this,
+ /*AllowNonLiteralTypes=*/true) ||
+ EStatus.HasSideEffects)
+ return false;
+ }
// At this point, any lifetime-extended temporaries are completely
// initialized.
diff --git a/clang/test/Modules/pr68702.cpp b/clang/test/Modules/pr68702.cpp
new file mode 100644
index 000000000000000..3f91a1001d1eecc
--- /dev/null
+++ b/clang/test/Modules/pr68702.cpp
@@ -0,0 +1,65 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-obj -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %t/main.cpp -o %t/main.o
+
+//--- V.h
+#ifndef V_H
+#define V_H
+
+class A {
+public:
+ constexpr A() { }
+ constexpr ~A() { }
+};
+
+template <typename T>
+class V {
+public:
+ V() = default;
+
+ constexpr V(int n, const A& a = A()) {}
+};
+
+#endif
+
+//--- inst1.h
+#include "V.h"
+
+static void inst1() {
+ V<int> v;
+}
+
+//--- inst2.h
+#include "V.h"
+
+static void inst2() {
+ V<int> v(100);
+}
+
+//--- module.modulemap
+module "M" {
+ export *
+ module "V.h" {
+ export *
+ header "V.h"
+ }
+ module "inst1.h" {
+ export *
+ header "inst1.h"
+ }
+}
+
+module "inst2.h" {
+ export *
+ header "inst2.h"
+}
+
+//--- main.cpp
+#include "V.h"
+#include "inst2.h"
+
+static void m() {
+ static V<int> v(100);
+}
|
} | ||
|
||
//--- module.modulemap | ||
module "M" { |
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 that the new standard nowadays? Can we use #pragma clang module build
and alike to express the module setup?
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.
split-file
is how many of the modules tests are written, and I find it very handy to reproduce setups with a number of smaller files...
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.
(not expressing any strong opinion on this patch in particular, but it'd be great if the pragmas were more used (but also, they're currently not perfect - my understanding is that -frewrite-imports
isn't totally robust yet/needs some more investment) so we had more test coverage for it because it'd be really great if it worked well/was considered when adding new features, etc - and I think it'd be a more direct way to write tests than needing to use the extra split-file invocation, etc (like you could copy a single file/command line to run a modules test, instead of splitting things, having a directory of files to deal with/copy/whatever, etc))
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.
While the change itself looks neat, I am curious about the reason how this interact with modules.
EStatus.HasSideEffects) | ||
return false; | ||
{ | ||
FullExpressionRAII Scope(Info); |
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 think we need to add a comment here similar to the one in EvaluateAsConstexpr(...)
in this case it would be A full-expression is ... an init-declarator ([dcl.decl]) or a mem-initializer
see https://eel.is/c++draft/intro.execution#5.4
CC @cor3ntin for second look
Please make sure you write a more complete description of the problem and why this solves the problem. The description is usually what goes into the git log and that is very useful for quickly understanding commits and tracking down problems. I know some folks edit the description on commit but honestly it is very helpful for the reviewers of your PR to have a full description up front. |
I think this change makes sense but I am not crazy about how we deal w/ full-expressions right now with these |
IIUC modules is incidental to the problem, it is just a way we run into an underlying issue that we are not dealing with full-expressions properly in this case. |
I can add the comment as requested, but for the other questions related to full expressions and modules I'd really need input from experts... |
ping @shafik @cor3ntin @ChuanqiXu9, how can we make progress here? |
The key point now is the rationale why this change relates to modules. It looks not good to proceed without understanding this. Otherwise we're playing with a black box... And the concrete method, ..., well, I guess we had no choice but debugging it hardly. For example, comparing the behavior of clang with and without the change. |
With modules, serialization might omit the outer ExprWithCleanups as it calls ParmVarDecl::getDefaultArg(). Complementary to fixing this in a separate change, make the code more robust by adding a FullExpressionRAII and avoid the llvm_unreachable in the added test clang/test/Modules/pr68702.cpp. Closes llvm#68702
b567f28
to
a55ca99
Compare
I finally had time to debug this: The reason for modules being involved here is because the serialization code calls Personally, I would argue that adding |
Thanks for looking into this. Good enough for me. Yeah the asymmetry between So personally I am fine with the current workaround with a |
Ping, is this ok to be accepted and landed?
You mean next to the comment I already added referring to the C++ standard? Can you formulate what I should put there? |
// A full-expression is ... an init-declarator ([dcl.decl]) or a | ||
// mem-initializer. | ||
// So we need to make sure temporary objects are destroyed after having | ||
// evaluated the expression (per C++23 [class.temporary]/p4). |
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.
// evaluated the expression (per C++23 [class.temporary]/p4). | |
// evaluated the expression (per C++23 [class.temporary]/p4). | |
// | |
// FIXME: Otherwise this may break test/Modules/pr68702.cpp. because the serialization code | |
// calls ParmVarDecl::getDefaultArg() which strips the outermost FullExpr, such as ExprWithCleanups. |
I mean the reason why this is related to modules. I feel the analysis is valuable.
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.
Done.
If it is not hurry, I prefer to wait @cor3ntin to have a look. But given the scale of the patch, it should be good too to land it in 1~2 weeks if there is no other comments. |
Well, this patch is up since almost three months now (!). Sure, we can keep carrying a similar fix downstream, but ideally I would really like to get rid of as many local changes as possible. That's not possible without proper review, but the current situation is quite unsatisfactory... |
Yeah, fully understood. I have a lot of similar experiences... 1~2 weeks is not long in comparing with 3 months. |
Please add a release note and address my previous comment: #69076 (comment) CC @cor3ntin |
I had already expanded the commit message with the full details, now also copied to the PR summary. Is that sufficient to address the comment? |
This change needs a release note. |
Done. |
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.
LGTM. Thanks for your patience.
With modules, serialization might omit the outer ExprWithCleanups as it calls ParmVarDecl::getDefaultArg(). Complementary to fixing this in a separate change, make the code more robust by adding a FullExpressionRAII and avoid the llvm_unreachable in the added test clang/test/Modules/pr68702.cpp. Closes llvm#68702
With modules, serialization might omit the outer
ExprWithCleanups
as it callsParmVarDecl::getDefaultArg()
. Complementary to fixing this in a separate change, make the code more robust by adding aFullExpressionRAII
and avoid thellvm_unreachable
in the added testclang/test/Modules/pr68702.cpp
.Closes #68702