[Bug c++/104384] coroutines: Heap corruption when initializing struct with co_await
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104384 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #1 from Steven Sun --- seems that 103909, 104384, 107288 are related (probably the same bug)
[Bug c++/107288] coroutines: Double-free of temporaries created in statement following co_await
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107288 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #3 from Steven Sun --- seems that 103909, 104384, 107288 are related (probably the same bug)
[Bug c++/103909] coroutines: co_yield of aggregate-initialized temporaries leads to segmentation faults.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103909 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #3 from Steven Sun --- seems that 103909, 104384, 107288 are related (probably the same bug)
[Bug analyzer/109027] [13 Regression] ICE: SIGSEGV (infinite recursion in ana::constraint_manager::eval_condition / ana::constraint_manager::impossible_derived_conditions_p) with -fanalyzer since r13-
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109027 --- Comment #3 from Steven Sun --- Oh, my reduced test case has the same infinite recursion occurring, where the `a+4` is binop_svalue (pointer_plus_expr, unaryop_svalue (nop_expr, conjured_svalue (, _iterator::_iterator (&__position, 0);, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct iterator’, ‘iterator __position’))), constant_svalue(‘long unsigned int’, 4)) the `b-4` is binop_svalue (pointer_plus_expr, sub_svalue (, conjured_svalue (, _iterator::_iterator (&__position, 0);, decl_region(globals, ‘struct Vector’, ‘Vector vec’)), field_region(decl_region(globals, ‘struct Vector’, ‘Vector vec’), ‘int *’, ‘int* Vector::_M_finish’)), constant_svalue(‘sizetype’, 18446744073709551612)) Current m_equiv_classes dump: new equiv_class region_svalue(‘struct Vector *’, decl_region(globals, ‘struct Vector’, ‘Vector vec’)) new equiv_class constant_svalue(‘void *’, 0B) new equiv_class region_svalue(‘struct _iterator *’, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct _iterator’, ‘’)) new equiv_class region_svalue(‘int * *’, field_region(decl_region(globals, ‘struct Vector’, ‘Vector vec’), ‘int *’, ‘int* Vector::_M_finish’)) new equiv_class region_svalue(‘struct _iterator *’, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct _iterator’, ‘_iterator it’)) new equiv_class sub_svalue (, conjured_svalue (, it = Vector::begin (this_10(D));, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct _iterator’, ‘_iterator it’)), field_region(decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct _iterator’, ‘_iterator it’), ‘int *’, ‘int* _iterator::_M_current’)) new equiv_class sub_svalue (, conjured_svalue (, it = Vector::begin (this_10(D));, decl_region(globals, ‘struct Vector’, ‘Vector vec’)), cast_region(field_region(decl_region(globals, ‘struct Vector’, ‘Vector vec’), ‘int *’, ‘int* Vector::_M_finish’), ‘int * const’)) new equiv_class region_svalue(‘struct _iterator *’, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct _iterator’, ‘’)) new equiv_class region_svalue(‘struct iterator *’, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct iterator’, ‘iterator __position’)) new equiv_class region_svalue(‘struct _iterator *’, decl_region(frame_region(‘_iterator::operator+’, index: 3, depth: 4), ‘struct _iterator’, ‘’)) new equiv_class region_svalue(‘int * const *’, decl_region(frame_region(‘_iterator::operator+’, index: 3, depth: 4), ‘int * const’, ‘’)) new equiv_class region_svalue(‘struct _iterator *’, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct _iterator’, ‘’)) new equiv_class binop_svalue (pointer_plus_expr, unaryop_svalue (nop_expr, conjured_svalue (, _iterator::_iterator (&__position, 0);, decl_region(frame_region(‘Vector::Filter’, index: 2, depth: 3), ‘struct iterator’, ‘iterator __position’))), constant_svalue(‘long unsigned int’, 4)) new equiv_class sub_svalue (, conjured_svalue (, _iterator::_iterator (&__position, 0);, decl_region(globals, ‘struct Vector’, ‘Vector vec’)), cast_region(field_region(decl_region(globals, ‘struct Vector’, ‘Vector vec’), ‘int *’, ‘int* Vector::_M_finish’), ‘int * const’)) new equiv_class binop_svalue (pointer_plus_expr, sub_svalue (, conjured_svalue (, _iterator::_iterator (&__position, 0);, decl_region(globals, ‘struct Vector’, ‘Vector vec’)), field_region(decl_region(globals, ‘struct Vector’, ‘Vector vec’), ‘int *’, ‘int* Vector::_M_finish’)), constant_svalue(‘sizetype’, 18446744073709551612))
[Bug analyzer/109027] [13 Regression] ICE: SIGSEGV (infinite recursion in ana::constraint_manager::eval_condition / ana::constraint_manager::impossible_derived_conditions_p) with -fanalyzer since r13-
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109027 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #2 from Steven Sun --- Created attachment 54862 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=54862=edit new test case New logic introduced in r13-6101-g4d3b7be281e73ecd causes infinite recursions. Specifically, `impossible_derived_conditions_p` will fail to escape this recursion. In this situation, for some `a`, `b`, we have `a+4` and `b-4` exist in different equivalent classes (of the `m_equiv_classes`). Then we try to compare `a == b-4`, `impossible_derived_conditions_p` then bring us to to check`a == b-4`, we'll look at `b == a+4`, since `a+4` is already in some equivalent class, we must know something about it. to check `b == a+4`, we'll look at `a == b-4`, since `b-4` is already in some equivalent class, we must know something about it. Then, it continues infinitely. We should bail this out. Also, it seems that the analyzer cannot recognize some template patterns, failing to enter any exit paths. This code path executes very rarely. -- While trying to simplify the original test case, I discovered my new test case is another infinite recursion but in a different code path.
[Bug analyzer/108767] O2 optimization has side effects on static analysis.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108767 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #2 from Steven Sun --- Like I just mentioned in #109190, you can check what is eaten by the analyzer. https://godbolt.org/z/Yqd11hGM6 the `for (d = 0; d <= 1; ++d)` was optimized as `for (d = 0; d != 2; ++d)` It looks like it will increase the range of `d` to `d != 2`.
[Bug analyzer/109190] GCC Static Analyzer cannot handle the initialization of an array with a for loop
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109190 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #4 from Steven Sun --- The analyzer is implemented as a ipa pass, which eats codes partially optimized by the middle end, or the optimizer. Your code presented to the analyzer looks like this in -O1 https://godbolt.org/z/KdaKW5Yae ``` int main () { int j; goto ; [100.00%] [local count: 536870913]: j_4 = j_1 + 1; [local count: 1073741824]: if (j_1 <= 0) goto ; [50.00%] else goto ; [50.00%] [local count: 536870913]: return 0; } ``` And it looks like this in -O2 https://godbolt.org/z/rrjdaM4WP ``` int main () { MEM[(int *)0B] = 1; return 0; } ``` The analyzer outputs should be definitely different. I am not here to what causes this, but in case you're interested, you can use godbolt to check all optimize passes.
[Bug c++/109283] Destructor of co_yield conditional argument called twice
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109283 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #1 from Steven Sun --- It is indeed a bug. I currently only investigated into the gcc-12, it generates something for ``` struct S{ /**/ }; bool w; co_yield w ? S{"a"} : S{"b"}; ``` pseudo-code for the generated gimple: ``` char __res[sizeof(S)]; char __a[sizeof(S)]; char __b[sizeof(S)]; new (__a) S("a"); new (__b) S("b"); if (w) memcpy(__res, __a, sizeof(S)); else memcpy(__res, __b, sizeof(S)); /* ... */ __b->~S(); __a->~S(); __c->~S(); ``` So, clearly there is at least 3 bugs here: i. `__res` is never constructed. ii. only one of the `__a` and `__b` should be constructed, not both. iii. the assignment is not corrected (it uses `gimple_assign` for value copy). If the ii is correctly implemented, iii will not happen. Though, the code will work fine on all trivial types. The correct code should be ``` char __res[sizeof(S)]; if (w) new (__res) S("a"); else new (__res) S("b"); /* ... */ __res->~S(); ```
[Bug c++/108218] [12/13 Regression] Constant arguments in the new expression is not checked in unevaluated operand since r12-5253-g4df7f8c79835d569
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 --- Comment #11 from Steven Sun --- (In reply to Andrew Pinski from comment #10) > https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2392 > > "potentially-evaluated". Oh, I realized that, According to the DR 2392 accepted as a DR at the November, 2022 meeting: https://cplusplus.github.io/CWG/issues/2392.html We should not evaluate that expression in the first dimension of `new` anymore. So this is not a bug. This also applys for expressions appearing in requirement-seq of requires-expressions. So surprising! (Correct me if I am wrong)
[Bug c++/108218] [12/13 Regression] Constant arguments in the new expression is not checked in unevaluated operand
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 --- Comment #7 from Steven Sun --- I got one simple idea as a workaround. I do not have the resources to do the tests. I agree anyone to take the following patch or the idea. >From 35b4186a0ed3671de603bed6df5fb1156f087581 Mon Sep 17 00:00:00 2001 From: Steven Sun Date: Sun, 25 Dec 2022 06:44:43 +0800 Subject: [PATCH] c++: escape unevaluated context in new-expression --- gcc/cp/init.cc | 5 + 1 file changed, 5 insertions(+) diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index b49a7ca9169..974ea95959e 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3929,7 +3929,12 @@ build_new (location_t loc, vec **placement, tree type, /* Try to determine the constant value only for the purposes of the diagnostic below but continue to use the original value and handle const folding later. */ + /* Escape the possible unevaluated context. Constant folding does + not work in unevaluated context, but is required in nelts. */ + int old_cp_unevaluated_operand = cp_unevaluated_operand; + cp_unevaluated_operand = false; const_tree cst_nelts = fold_non_dependent_expr (nelts, complain); + cp_unevaluated_operand = old_cp_unevaluated_operand; /* The expression in a noptr-new-declarator is erroneous if it's of non-class type and its value before converting to std::size_t is -- 2.34.1
[Bug c++/108218] [12/13 Regression] Constant arguments in the new expression is not checked in unevaluated operand
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 --- Comment #6 from Steven Sun --- g:4df7f8c79835d56928f51f9e674d326300936e8e c++: don't do constexpr folding in unevaluated context The implicit constexpr patch revealed that we were doing constant evaluation of arbitrary expressions in unevaluated contexts, leading to failure when we tried to evaluate e.g. a call to declval. This is wrong more generally; only manifestly-constant-evaluated expressions should be evaluated within an unevaluated operand. Making this change revealed a case we were failing to mark as manifestly constant-evaluated. gcc/cp/ChangeLog: * constexpr.c (maybe_constant_value): Don't evaluate in an unevaluated operand unless manifestly const-evaluated. (fold_non_dependent_expr_template): Likewise. * decl.c (compute_array_index_type_loc): This context is manifestly constant-evaluated.
[Bug c++/108218] [12/13 Regression] Constant arguments in the new expression is not checked in unevaluated operand
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 --- Comment #5 from Steven Sun --- h:4df7f8c79835d56928f51f9e674d326300936e8e sorry, copied wrong hash code
[Bug c++/108218] [12/13 Regression] Constant arguments in the new expression is not checked in unevaluated operand
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 --- Comment #3 from Steven Sun --- Bisecting tells me: 2551cd4f9bc1afee444a56e03c1cee6899593da9 is bad adcfd2c45c3523d74279b5fcac1d7c6c34dd1382 is good I think commit ddd25bd1a7c8f456bc914e34b77d43f39a1062d4 might be the root cause.
[Bug c++/108218] [12 Regression] Constant arguments in the new expression is not checked in unevaluated operand
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 --- Comment #1 from Steven Sun --- My concern is that, expressions within the require expressions are also considered as "unevaluated operands". Thus, the following concept is evaluated as true, but the program is ill-formed and does not compile (since gcc 12) https://godbolt.org/z/bcc398chG ``` template concept C = requires { new int[(int)sizeof(T) - 4]; }; template requires C class CC { CC() { new int[(int)sizeof(T) - 4]; } }; template class CC; ``` : In instantiation of 'CC::CC() [with T = char]': :16:16: required from here :12:32: error: size '-3' of array is negative 12 | new int[(int)sizeof(T) - 4]; | ~~~^~~
[Bug c++/108218] New: [12 Regression] Constant arguments in the new expression is not checked in unevaluated operand
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108218 Bug ID: 108218 Summary: [12 Regression] Constant arguments in the new expression is not checked in unevaluated operand Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: StevenSun2021 at hotmail dot com Target Milestone: --- ``` int main() { decltype(new int[-1]) a; // compiles with g++-12! <- regression here // does not compile with g++-11 auto b = new int[-1];// does not compile with g++-12 // does not compile with g++-11 } ``` https://godbolt.org/z/aMGMrbfrd expected behavior: if, after conversion to std::size_t, the first dimension is a core constant expression and it is potentially evaluated, the program is ill-formed. https://en.cppreference.com/w/cpp/language/new gcc(<=11.3 (current version)) and clang(>=3) does this check.
[Bug c++/101681] PMF comparison to nullptr is not considered a constexpr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101681 --- Comment #3 from Steven Sun --- By the way, in the current design, the class definition is passed twice in order we can see every member data/function declaration before parsing NSDMI and member functions. The class is complete after parsing all declaration, which means `::f == nullptr` can reduce to false since that. So, under current design, the following code compiles on GCC. https://godbolt.org/z/fMTsf4KoM ``` struct C { C() { static_assert(::f != 0); // complete type } void f() noexcept(::f != 0) { static_assert(::f != 0); // complete type } static_assert(__builtin_constant_p(::f));// incomplete type static_assert(!__builtin_constant_p(::f == 0)); // incomplete type }; static_assert(::f != 0); // complete type ```
[Bug c++/101681] PMF comparison to nullptr is not considered a constexpr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101681 --- Comment #2 from Steven Sun --- The root cause for this is that the compiler forbids constant folding when involving PMF of an incomplete class. https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/expr.c;h=d16d1896f2ddd08264b389b02b9640cca332ec13;hb=refs/heads/master#l42 (gcc/cp/expr.c) > 42 /* We can't lower this until the class is complete. */ > 43 if (!COMPLETE_TYPE_P (DECL_CONTEXT (member))) > 44 return cst; If we comment this `if`, the constant folding will succeed at (gcc/cp/expr.c) > 67 expand_ptrmemfunc_cst (cst, , ); > 68 cst = build_ptrmemfunc1 (type, delta, pfn); solving everything.
[Bug c++/101681] PMF comparison to nullptr is not considered a constexpr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101681 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #1 from Steven Sun --- The following program compiles. https://godbolt.org/z/aTvchYxYW ``` struct C { void f() {} static_assert(__builtin_constant_p(::f)); static_assert(!__builtin_constant_p(::f == nullptr)); // not nonzero yet }; static_assert(__builtin_constant_p(::f == nullptr)); // nonzero now struct D { void f() {} static_assert(__builtin_constant_p(::f == nullptr)); static_assert(!__builtin_constant_p(::f == nullptr)); }; static_assert(__builtin_constant_p(::f == nullptr)); static_assert(__builtin_constant_p(::f == nullptr)); ``` Looks that the `::f` is known to be constexpr right after the function was parsed. But only when the class completely parsed, its value was assigned. We can then compare it to nullptr. To make code in comment0 accepted, we need some kind of `not null' mark on the expression tree. 0ne possible way is to assign the `::f` in advance, right after it was parsed.
[Bug c++/101717] [12 Regression] ICE capturing static member within stateless generic lambda
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101717 --- Comment #5 from Steven Sun --- (In reply to Andrew Pinski from comment #4) Thanks! (In reply to myself from comment #3) > The program seems never think of a situation "a lambda inside a lambda > inside a NSDMI`. We need to amend the logic here. edit to: The program seems never think of a situation "member function call inside a generic lambda inside a lambda inside a NSDMI`. We need to amend the logic here. - The direct cause of failure is in g:91e534b0d ``` if (!containing_function && !COMPLETE_TYPE_P (closure)) /* If we're parsing a lambda in a non-local class, we can find the fake 'this' in scope_chain. */ init = scope_chain->x_current_class_ptr; ``` This part of logic is to find the potential `this` since there is a (static) member function call `f`. Refer to the following comments: /* For the overload resolution we need to find the actual `this` that would be captured if the call turns out to be to a non-static member function. Do not actually capture it at this point. */ // in function `build_new_method_call_1` in `gcc/cp/call.c` - As for example in comment 1: `scope_chain->x_current_class_ptr` is correctly set when parsing ``` [=](auto) { f(); } ``` But it was soon incorrectly set when instantiating the same lambda, i.e. parsing ``` [=](auto) { f(); }() ``` This failure only affectes the potential `this` pointer inside the ``` [=](auto) { f(); } ``` But since here needs no `this` pointer, deleting that problematical `gcc_checking_assert` is actually a potential fix for this problem.
[Bug c++/101717] [12 Regression] ICE capturing static member within stateless generic lambda
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101717 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #3 from Steven Sun --- This bug is not introduced in GCC 12. The relevant code fragment is last edited by g:91e534b0d in `gcc/cp/lambda.c` ``` gcc_checking_assert (init && (TREE_TYPE (TREE_TYPE (init)) == current_nonlambda_class_type ())); ``` The assertion fails since long ago. (init == 0 in this case) Before GCC 12, the `gcc_checking_assert` is `(void)0` in release version, leaving everything fine. Somehow `gcc_checking_assert` starts working now, and aborts the program. My insight on the problem: The program seems never think of a situation "a lambda inside a lambda inside a NSDMI`. We need to amend the logic here. "here" means https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/lambda.c;h=2e9d38bbe832702804ddcaffc4024ce930a74843;hb=refs/heads/master#l755 By the way, does anyone know other magics like g:hash?
[Bug c++/100877] g++ freezes system by consuming infinite amount of memory
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100877 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #2 from Steven Sun --- Feng use a non-exist member in your definition of template< Expression Ex, Place_Holder Ph, Expression Ey > auto replace_placeholder_with_expression( Ex const& ex, Ph const& old_place_holder, Ey const& new_expression ) namely `ex.reset_action_`. It the one and only bug in your code. It compiles in a few seconds after being fixed. CONCLUSION: No bug in GCC but a stupid bug in Feng's code. But interestingly, GCC eats so much memory to dump an error message involving lambdas, template lambdas, and templates (eats 20G in my desktop, >400G in Feng's cluster).
[Bug c++/100877] g++ freezes system by consuming infinite amount of memory
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100877 --- Comment #1 from Steven Sun --- I look at the call stack. Most of the time is wasted on `dump_template_parms` in `gcc/cp/error.c`. I commented several functions calling it: (I'm using stage-1 compiler) `announce_function` in `gcc/toplev.c` `push_tinst_level_loc` in `gcc/cp/pt.c` `cp_printer` in `gcc/cp/error.c` (directly return true) Then I got the output after a few seconds. -- examples/../include/./model.hpp: In instantiation of ‘’: examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:61:77: required from ‘’ examples/../include/./model.hpp:55:147: [ skipping 8 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ] examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:55:147: recursively required from ‘’ examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:60:77: required from ‘’ examples/../include/./model.hpp:60:77: recursively required from ‘’ examples/../include/./model.hpp:55:147: recursively required from ‘’ examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:55:147: recursively required from ‘’ examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:60:77: required from ‘’ examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:382:55: required from ‘’ examples/dcgan.cc:48:43: required from here examples/../include/./model.hpp:59:96: error: ‘’ has no member named ‘’ -- But I cannot give the output. Because the dumping process will lead to an out of memory. If I disable member access check, it gives an error - examples/../include/./model.hpp: In instantiation of ‘’: examples/../include/./model.hpp:55:147: recursively required from ‘’ examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:60:77: required from ‘’ examples/../include/./model.hpp:55:147: required from ‘’ examples/../include/./model.hpp:382:55: required from ‘’ examples/dcgan.cc:48:43: required from here examples/../include/./model.hpp:60:77: error: use of ‘’ before deduction of ‘auto’ It's the same source location! and it is in your definition of template< Expression Ex, Place_Holder Ph, Expression Ey > auto replace_placeholder_with_expression( Ex const& ex, Ph const& old_place_holder, Ey const& new_expression )
[Bug c++/99686] ICE when using both concepts and full specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 --- Comment #8 from Steven Sun --- under c++17 Step 4 needs `types_match == 1` [at 1] but, its value is zero, which is caused by `function_requirements_equivalent_p` [at 3] returns 0 [at 2] . [1] https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/decl.c;h=316ad4c1426940bd4f51197a6297eefc24064fec;hb=HEAD#l1481 [2] https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/decl.c;h=316ad4c1426940bd4f51197a6297eefc24064fec;hb=HEAD#l1052 [3] https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/decl.c;h=316ad4c1426940bd4f51197a6297eefc24064fec;hb=HEAD#l944 [4] https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/pt.c;h=36a8cb5df5d36337c18e1547e775b747f59a087f;hb=HEAD#l3510 In `function_requirements_equivalent_p` [at 3], the comparison is different for cxx20 and before. According to the comments, before c++20, only the combined constraints are compaired. -- By the way, for those two primary function templates in comment 1. Before cxx20, they are regard as equivalent heads [at 4] inequivalent requirements [at 3] Since cxx20, they are regard as inequivalent heads [at 4] equivalent requirements [at 3] If I change both [3], [4], forcing cxx17 using cxx20 standard, everything works. - Many invariants are broken here. They cause this bug together: A failure in requirements comparison caused no reregistration, which leads to overload between implicit instatntiation. The full specialzation is already parsed, leaving a null `cfun` state. Then it tries to instatiate the function body and everything crashes, They are all `by design` in a sense. How to fix it is not only a technical issue, but a design choice. If any senior gcc developer sees this, help me. - By the way, I don't think this bug would matter too much, since no one really uses concepts before c++20. I am just curious.
[Bug c++/99686] ICE when using both concepts and full specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 --- Comment #7 from Steven Sun --- After digging for two days, I think I may know what's happening inside. Under std=c++20 and my code in comment 1, the flow when parsing a full function specialization would be 1. Found a full specialization of function. 2. Instantiate all possible primary function templates. 3. Find the most suitable instantiation (here, the concept constrained is chosen) 4. Then replace it with full specialization. (this is done in `reregister_specialization` in `gcc/cp/pt.c`) So when performing overloading in the main function, there would be one instantiation and one full specialization to choose. (To be specific, those two are in the hash table `decl_specialization` defined in `gcc/cp/pt.c`) While in the c++17 mode, step 4 is broken. So there will be 2 implicit instantiation to choose when overloading. Step 4 is performed in the function `duplicate_decls` defined in `gcc/cp/decl.c`. Certain conditions must be satisfied to replace the instantiation. The one failed here is: "the compiler thinks the full specialization has a different concepts constraint with primary template (because the primary template has contraints but the full specialization doesn't)" So the reregistration is never triggered. This is the source of the bug. After getting the whole picture, I simplify the test case as https://godbolt.org/z/9MM6rEf77 --- std=c++17 -fconcepts template requires requires(T t) { ++t; } void func(T &) { } template <> void func(int&& arg) { } int main() { func(1); } --- I'll give more details in the next comment in case any developer would like to fix it.
[Bug c++/99686] ICE when using both concepts and full specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 --- Comment #6 from Steven Sun --- While in C++20, the complier thinks it's unnecessary to instatiate a new template. Just use the full specialization! Thus, this bug wouldn't exist at first place. Intuitively, I am in favor of the compiler's C++20 behavior -- use full specialization anyway. Clang 12 and MSVC latest also have this behavior (choose full specialization). I don't know how to contribute to gcc. If anyone would like to fix this bug, my recommendation would be: Make the compiler in C++17 mode think it's unnecessary to instantiate a new function when full specialzation is provided, which resulting the same behavior as C++20 mode and as other compilers.
[Bug c++/99686] ICE when using both concepts and full specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 --- Comment #5 from Steven Sun --- I learn a little about gcc recently. I think I got a vague idea of what's going on inside. In c++17 mode with concepts, and with my code in comment 1. The compiler decides to instantiate from the concept constrained template. Usually the compiler should generate a new function on the AST, but this time there's already one function (fully specialized) on the AST. So, the function `start_preparsed_function` in the below link returns at the quoted line. It's thinking "Ah! There's already a function, no need to allocate a new one." https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/decl.c;h=316ad4c1426940bd4f51197a6297eefc24064fec;hb=HEAD#l16696 Then the flow goes back to the function in the link below. It's thinking "Since I'm gonna add a new function, new function is allocated on AST. Everything should be prepared for me!" More specifially, it will assume the `cfun` in the correct state set by the `start_preparsed_function`. But `cfun` is null, since the `start_preparsed_function` returns early. This is the direct cause of segfault, which triggered at the line below. https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/pt.c;h=36a8cb5df5d36337c18e1547e775b747f59a087f;hb=HEAD#l25932 In conclusion, The compiler doesn't consider there would be a situation that an instatiation is still needed when full specialzation is provided. This break the invariants.
[Bug c++/99686] ICE when using both concepts and full specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 --- Comment #3 from Steven Sun --- @W E Brown: I got your idea. So are all uses like this ill-formed? This seems unexpected for me. I would expect the complete specialization is full specialization for both primary templates. I also find facts that support your idea: If I modify the full specialization to template <> void func (int&& arg){} It compiles. See https://godbolt.org/z/fh9Mx7Krr If I modify the full specialization to template <> void func (int&& arg){} It produce the same ICE output as comment 1. See https://godbolt.org/z/eMa5YcrrE It looks like the compiler doesn't knows which primary template to specialize. I look up in the C++20 standard, and did not find anything about 2 primary templates exists. The code in Comment 1 compiles for g++ 6.1 to 9.3, then breaks since 10.1 (all under -std=c++17 -fconcepts). In conclusion, this makes sences but I didn't see that coming. Anyway, I think a possible improvement is make ICE to an error of "ambigous full specialization". Or even better, a change in C++23 standard.
[Bug c++/99686] ICE when concepts on C++17 when providing both T&& and const T& specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 --- Comment #1 from Steven Sun --- The compiler args are only "g++ -fconcepts -std=c++17" It should choose the full specialization func(int &&), while the compiler aborts during the instatiation of the partial specialization (using concepts). If either the partial or the full specialzation is removed, it compiles. New online compiler link: https://godbolt.org/z/fK5G61 - template void func(T &) { } template requires requires(T t) { ++t; } void func(T &) { } template <> void func(int &) { } int main() { func(1); // I am expecting func(int&&) } - Error: In instantiation of ‘void func(T&&) [with T = int]’: internal compiler error: Segmentation fault 11 | } | ^ Please submit a full bug report,
[Bug c++/99686] New: ICE when concepts on C++17 when providing both T&& and const T& specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686 Bug ID: 99686 Summary: ICE when concepts on C++17 when providing both T&& and const T& specialization Product: gcc Version: 10.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: StevenSun2021 at hotmail dot com Target Milestone: --- This problem occurs only when using std=c++17 and -fconcepts. It compiles when using std=c++20. I also have an online compiler link for this. https://godbolt.org/z/W9r6Wx - template void func(T &) { } template requires requires(T t) { ++t; } void func(T &) { } template <> void func(int &) { } template <> void func(const int ) { } int main() { func(1); // I am expecting func(int&&) }
[Bug c++/99019] New: A nicer error hint, for cpp modules, if missing headers
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99019 Bug ID: 99019 Summary: A nicer error hint, for cpp modules, if missing headers Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: StevenSun2021 at hotmail dot com Target Milestone: --- This is not a bug but can be improved. If I forget to include headers, like the following --- export module B; export void foo() { std::cout << 1; } --- Compile it with g++ 11, I get an error hint: --- test.cpp: In function ‘void foo()’: test.cpp:5:10: error: ‘cout’ is not a member of ‘std’ 5 | std::cout << 1; | ^~~~ test.cpp:1:1: note: ‘std::cout’ is defined in header ‘’; did you forget to ‘#include ’? +++ |+#include 1 | export module B; --- Actually it should be +++ |+module; +++ |+#include 1 | export module B; Using a build of brunch devel/c++-modules. Built 3 days ago.
[Bug c++/98944] [modules] Failed to read compiled module with a non-exported partition.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98944 Steven Sun changed: What|Removed |Added CC||StevenSun2021 at hotmail dot com --- Comment #1 from Steven Sun --- I met the same problem. - Three days ago, I pull from the repository and then compile the gnu c++ compiler in the devel/c++-modules branch. system: ubuntu-20.04 x86_64 configured with: --disable-multilib I took the same exaple as you, which is in the final working draft n4861 [modules.unit]. I think the compile order should be tu3 tu2 tu1 tu4, because the compiler tells me I cannot import before build. So I compile it as g++ -fmodules-ts -std=c++20 -c 3.cc -o 3.o g++ -fmodules-ts -std=c++20 -c 2.cc -o 2.o g++ -fmodules-ts -std=c++20 -c 1.cc -o 1.o g++ -fmodules-ts -std=c++20 -c 4.cc -o 4.o The compiling for 4.cc got an error -- In module imported at 4.cc:1:1: A: error: failed to read compiled module: Bad file data A: note: compiled module file is ‘gcm.cache/A.gcm’ A: fatal error: returning to the gate for a mechanical issue compilation terminated. -- Then I took a peek into the gcm.cache/A.gcm, using readelf. Found that there's already a section header named bar. So I removed the line `import :Internals;` in 4.cc and it compiles. Anyway, I don't know if that is a bug. Maybe the standard is different from the final working draft. I am not sure.