[Bug c++/99625] New: GCC does not detect narrowing in aggregate initialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99625 Bug ID: 99625 Summary: GCC does not detect narrowing in aggregate initialization Product: gcc Version: 10.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Testcase: extern long double l; struct S { S(int) {} }; S s[] = { l }; This is supposed to be ill-formed because of narrowing. GCC does not reject the code, nor it warns (as it usually does for narrowing). The relevant rule is in [dcl.init.aggr]: https://eel.is/c++draft/dcl.init.aggr#4.2.sentence-2 > Otherwise, the element is copy-initialized from the corresponding > initializer-clause or is initialized with the brace-or-equal-initializer of > the corresponding designated-initializer-clause. > If that initializer is of the form assignment-expression or = > assignment-expression and a narrowing conversion ([dcl.init.list]) is > required to convert the expression, the program is ill-formed. That rule has been changed in C++20 with designated initializers, but the same one was also there for C++17 and before, e.g. https://timsong-cpp.github.io/cppwp/n4659/dcl.init.aggr#3 For comparison, Clang accepts with no warnings, but MSVC warns about narrowing.
[Bug libstdc++/96416] address_of() is broken by static_assert in pointer_traits
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 Giuseppe D'Angelo changed: What|Removed |Added CC||dangelog at gmail dot com --- Comment #9 from Giuseppe D'Angelo --- Hi, Stumbled across this indeed when trying to use contiguous iterators. Sure enough, pointer_traits for them is ill-formed. But then I don't understand why the "otherwise to_address(p.operator->())" part is in the Standard at all, if it can never be used. Has this been raised as a library defect? And are you recommending that everyone who defines their custom contiguous iterators specializes pointer_traits for them? Call it _quite_ annoying...
[Bug libstdc++/96416] address_of() is broken by static_assert in pointer_traits
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 --- Comment #10 from Giuseppe D'Angelo --- (By the way, finding this bug is quite hard. Could "address_of" be changed to "to_address" , in the bug description? I think that's the intended meaning. And, "to_pointer", mentioned a few times, doesn't exist.)
[Bug libstdc++/96416] to_address() is broken by static_assert in pointer_traits
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 --- Comment #14 from Giuseppe D'Angelo --- Hello, (In reply to Glen Joseph Fernandes from comment #11) > > if it can never be used. > > You're misunderstanding. to_address(p) requires that pointer_traits is > valid. It just doesn't need to have a to_address member function. Thank you for clarifying this. I think the wording in the standard is very unfortunate, but combined with the realization that pointer_traits isn't SFINAE-friendly, then it's the only intended meaning. > If (for contiguous iterators, which came later) you want pointer_traits > to be valid even when X does not have element_type, that is a design change > to pointer_traits. One might claim that pointer_traits should become SFINAE-friendly (like C++17's iterator_traits), but sure, that's a different design question and not necessarily needed here. (In reply to Jonathan Wakely from comment #12) > (In reply to Giuseppe D'Angelo from comment #10) > > (By the way, finding this bug is quite hard. Could "address_of" be changed > > to "to_address" , in the bug description? > > Done. Thank you! (In reply to Arthur O'Dwyer from comment #13) > > And are you recommending that everyone who defines their custom contiguous > > iterators specializes pointer_traits for them? Call it _quite_ annoying... > > Definitely not! When you define a contiguous iterator type, you should just > give it a sixth nested typedef alongside the other five (or three in C++20): > `using element_type = value_type;`. This enables contiguous-iterator > machinery. > See > https://stackoverflow.com/questions/65712091/in-c20-how-do-i-write-a- > contiguous-iterator/66050521#66050521 This gets evil really quick: the presence of both value_type and element_type in an contiguous iterator will make you smash face-first against LWG3446, which isn't implemented in GCC 10 AFAICS. https://cplusplus.github.io/LWG/issue3446 What's more, the accepted resolution wording for it appears to be wrong: template requires has-member-element-type && same_as, remove_cv_t> struct indirectly_readable_traits : cond-value-type { }; For const iterators, value_type is actually different from element_type (!). Thankfully libstdc++ seems to have considered this as a non-standard extension, https://github.com/gcc-mirror/gcc/commit/186aa6304570e15065f31482e9c27326a3a6679f To summarize: * should a wording defect be raised against std::to_address(Ptr), to state that pointer_traits being well-formed is actually a prerequisite? * should LWG3446's resolution be amended? * if there's going to be a GCC 10.3, is the commit above solving LWG3446 going to be cherry-picked into it? Otherwise, either one blacklists GCC 10, or has to specialize pointer_traits there as a workaround (?). Thank you all for the insightful comments.
[Bug libstdc++/96416] to_address() is broken by static_assert in pointer_traits
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 --- Comment #18 from Giuseppe D'Angelo --- Hello, (In reply to Jonathan Wakely from comment #17) > (In reply to Giuseppe D'Angelo from comment #14) > > To summarize: > > > > * should a wording defect be raised against std::to_address(Ptr), to state > > that pointer_traits being well-formed is actually a prerequisite? > > I'd prefer if pointer_traits was just SFINAE friendly. I guess that's a reasonable thing to wish for, given I'm not the first falling for it; I hope I'll be the last :) > > * should LWG3446's resolution be amended? > > See https://cplusplus.github.io/LWG/issue3541 > > > * if there's going to be a GCC 10.3, is the commit above solving LWG3446 > > going to be cherry-picked into it? Otherwise, either one blacklists GCC 10, > > or has to specialize pointer_traits there as a workaround (?). > > It missed the 10.3 release, but it's on the gcc-10 branch as r10-9698, which > will be in GCC 10.4: > https://gcc.gnu.org/g:32a859531e854382c18abf0b14a306d83f793eb5 > That also includes the fix for LWG 3541. Thank you very much for the new issue and the cherry-pick of the fix.
[Bug tree-optimization/87952] Missed optimization for std::get_if on std::variant
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87952 Giuseppe D'Angelo changed: What|Removed |Added CC||dangelog at gmail dot com --- Comment #2 from Giuseppe D'Angelo --- Still valid as 10.2. There's just been some discussion related to this missed optimization on the std-proposals mailing list. It's also worth noticing that neither GCC nor Clang remove the branch from some slightly different code: int& test(std::variant &v) { return *std::get_if(&v); } GCC 10.2 generates: test(std::variant&): xorl %eax, %eax cmpb $0, 8(%rdi) cmove %rdi, %rax ret Clang 11 generates: test(std::__1::variant&): # @test(std::__1::variant&) xorl %eax, %eax cmpl $0, 8(%rdi) cmoveq %rdi, %rax retq If one pushes things a little bit, both compilers remove the branch: int& test(std::variant& v) { auto result = std::get_if(&v); if (!result) __builtin_unreachable(); return *result; } GCC: test(std::variant&): movq %rdi, %rax ret Clang: test(std::__1::variant&): # @test(std::__1::variant&) movq %rdi, %rax retq Could you please elaborate on what you mean by "might end up as a security issue"?
[Bug c++/99032] New: GCC accepts attributes on friend declarations (not definitions)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99032 Bug ID: 99032 Summary: GCC accepts attributes on friend declarations (not definitions) Product: gcc Version: 10.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, The following code is accepted by GCC 10.2: struct S { [[deprecated]] friend void f(); }; No errors and no warnings are generated under -Wall -Wextra -pedantic. The code is however ill-formed: an attribute cannot appear on a friend declaration which isn't also a definition: https://eel.is/c++draft/dcl.attr#grammar-5.sentence-3 If an attribute-specifier-seq appertains to a friend declaration ([class.friend]), that declaration shall be a definition. For comparison, Clang rejects this, and MSVC accepts it (without warnings).
[Bug middle-end/54202] Overeager warning about freeing non-heap objects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54202 Giuseppe D'Angelo changed: What|Removed |Added CC||dangelog at gmail dot com --- Comment #8 from Giuseppe D'Angelo --- The original testcase by Thiago still fails with GCC 11. Unfortunately, GCC 11 decided to turn -Wfree-nonheap-object on by default (!), resulting in false positives for Qt users (containers in Qt use this pattern). For instance https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qlinkedlist.h?h=5.15 struct QT_DEPRECATED_VERSION_5_15 QLinkedListData { QLinkedListData *n, *p; QtPrivate::RefCount ref; // set to -1 for shared_null int size; uint sharable : 1; Q_CORE_EXPORT static const QLinkedListData shared_null; }; template inline QLinkedList::~QLinkedList() { if (!d->ref.deref()) freeData(d); // never called on shared_null because of the check } template void QLinkedList::freeData(QLinkedListData *x) { // ... delete x; // -Wfree-nonheap-object here }
[Bug c++/100796] New: [11 Regression] GCC does not honor #pragma diagnostic ignored when using the integrated preprocessor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100796 Bug ID: 100796 Summary: [11 Regression] GCC does not honor #pragma diagnostic ignored when using the integrated preprocessor Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, When building the qtbase `dev` branch with GCC 11, a bunch of warnings are generated even in the presence of a ignoring pragma. For a bit of context, in Qt there's a macro called Q_OBJECT that users can add to their classes; this macro expands to a series of declarations, including a couple of virtuals. These may raise -Wsuggest-override warnings, in user code, so such warnings are suppressed via pragmas (as part of the Q_OBJECT macro itself). GCC 10 honors the pragmas and doesn't raise warnings, but GCC 11 doesn't honor them, resulting in warnings like include/QtCore/../../../src/corelib/kernel/qtmetamacros.h:159:32: error: ‘virtual const QMetaObject* QTextObject::metaObject() const’ can be marked override [-Werror=suggest-override] 159 | virtual const QMetaObject *metaObject() const; \ |^~ include/QtGui/../../../src/gui/text/qtextobject.h:62:5: note: in expansion of macro ‘Q_OBJECT’ 62 | Q_OBJECT | ^~~~ include/QtCore/../../../src/corelib/kernel/qtmetamacros.h:160:19: error: ‘virtual void* QTextObject::qt_metacast(const char*)’ can be marked override [-Werror=suggest-override] 160 | virtual void *qt_metacast(const char *); \ | ^~~ include/QtGui/../../../src/gui/text/qtextobject.h:62:5: note: in expansion of macro ‘Q_OBJECT’ 62 | Q_OBJECT | ^~~~ And so on and so forth. Now, the peculiarity of this bug is that if you disable the integrated preprocessor via -no-integrated-cpp then everything works fine. Similarly, if you take a preprocessed output and compile *that*, then no warnings are raised. I therefore suspect a regression in the integrated preprocessor. For this reason I'm actually unable to attach a testcase: a preprocessed output compiles just fine. Please advise as of what kind of test I could do / provide to help you track this one down. If you wish to try and compile Qt yourself, then it's relatively easy: 1) clone git://code.qt.io/qt/qtbase.git , checkout dev 2) get a very recent CMake 3) mkdir build 4) (with GCC 11 in PATH, or force it via CC/CXX env) cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DQT_BUILD_EXAMPLES_BY_DEFAULT=OFF -DQT_BUILD_TESTS_BY_DEFAULT=OFF -DFEATURE_developer_build=ON ../path/to/qtbase 5) ninja Upstream bug: https://bugreports.qt.io/browse/QTBUG-93360
[Bug c++/100796] [11 Regression] GCC does not honor #pragma diagnostic ignored when using the integrated preprocessor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100796 --- Comment #2 from Giuseppe D'Angelo --- Well, GCC 8-9-10 don't have this problem at all for us. This appeared only when upgrading to 11. Anyways, I'm not sure if it's the same issue. PR 53431 seems to be about the preprocessor itself ignoring the pragmas -- like raising -Wundef even under a pragma. Here is not quite about the preprocessor (in fact, the not-honored pragma can only be honored by the compiler, it's about -Wsuggest-override). The compiler seems to ignore that pragma in _random_ places (it's very inconsistent; the majority of code is not flagged, except for a few occurrences). If I run the preprocessor manually, the pragma is still correctly present in the preprocessed output. However: running the compiler over that preprocessed output does NOT raise the warning. That leads to the fact that adding -no-integrated-cpp is a successful workaround; this makes me think something broke in there...?
[Bug c++/100796] [11 Regression] GCC does not honor #pragma diagnostic ignored when using the integrated preprocessor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100796 --- Comment #4 from Giuseppe D'Angelo --- Created attachment 51011 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=51011&action=edit testcase Hi, I've tried to "carve" a subset of files that show the problem. Apologies for not really being minimal. How to reproduce: 1) uncompress 2) cd $dir/home/peppe/projects/src/qt5/qtbase/build 3) (with c++ = GCC 11) run c++ -DQT_CONCURRENT_LIB -DQT_CORE_LIB -DQT_TESTCASE_BUILDDIR=\"/home/peppe/projects/src/qt5/qtbase/build/tests/auto/corelib/io/qurl\" -DQT_TESTCASE_SOURCEDIR=\"/home/peppe/projects/src/qt5/qtbase/tests/auto/corelib/io/qurl\" -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -Itests/auto/corelib/io/qurl/tst_qurl_autogen/include -I../tests/auto/corelib/io/qurl -Itests/auto/corelib/io/qurl -Iinclude -Iinclude/QtCore -I../mkspecs/linux-g++ -Iinclude/QtTest -Iinclude/QtConcurrent -Isrc/testlib -Iinclude/QtTest/6.2.0 -Iinclude/QtTest/6.2.0/QtTest -Isrc/corelib -Iinclude/QtCore/6.2.0 -Iinclude/QtCore/6.2.0/QtCore -g -fPIE -fvisibility=hidden -fvisibility-inlines-hidden -Wall -Wextra -fPIC -pthread -Wsuggest-override -std=gnu++2a -o /dev/null -c ../tests/auto/corelib/io/qurl/tst_qurl.cpp That for me generates a bunch of false warnings such as > include/QtCore/../../../src/corelib/kernel/qtmetamacros.h:159:32: warning: > ‘virtual const QMetaObject* QSocketNotifier::metaObject() const’ can be > marked override [-Wsuggest-override] > 159 | virtual const QMetaObject *metaObject() const; \ > |^~ > include/QtCore/../../../src/corelib/kernel/qsocketnotifier.h:51:5: note: in > expansion of macro ‘Q_OBJECT’ >51 | Q_OBJECT > | ^~~~ and many more. As mentioned before: adding -no-integrated-cpp to the command line, and/or splitting the compilation in explicit preprocessing+compilation, makes the warnings disappear. Please let me know if the testcase works or if I forgot to add something (hoping that system headers don't make a difference, anyways, I'm testing under Ubuntu 20.04).
[Bug c++/100796] [11 Regression] GCC does not honor #pragma diagnostic ignored when using the integrated preprocessor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100796 --- Comment #6 from Giuseppe D'Angelo --- Hi, Wow, that was quick! I can't really judge the merit of the patch, but I've picked it on top of the GCC 11.1.0 tarball and can confirm that it seems to fix all the warnings for us. Thank you very much!
[Bug middle-end/101134] New: Bogus -Wstringop-overflow warning about non-existent overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134 Bug ID: 101134 Summary: Bogus -Wstringop-overflow warning about non-existent overflow Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hello, This reduced testcase from Qt raises a -Wstring-overflow warning on GCC 11.1 when compiling under -O2 -g -Wall -Wextra: #include #include struct QTestCharBuffer { enum { InitialSize = 512 }; inline QTestCharBuffer() : buf(staticBuf) { staticBuf[0] = '\0'; } QTestCharBuffer(const QTestCharBuffer &) = delete; QTestCharBuffer &operator=(const QTestCharBuffer &) = delete; inline ~QTestCharBuffer() { if (buf != staticBuf) free(buf); } inline char *data() { return buf; } inline int size() const { return _size; } inline bool reset(int newSize) { char *newBuf = nullptr; if (buf == staticBuf) { // if we point to our internal buffer, we need to malloc first newBuf = reinterpret_cast(malloc(newSize)); } else { // if we already malloc'ed, just realloc newBuf = reinterpret_cast(realloc(buf, newSize)); } // if the allocation went wrong (newBuf == 0), we leave the object as is if (!newBuf) return false; _size = newSize; buf = newBuf; return true; } private: int _size = InitialSize; char* buf; char staticBuf[InitialSize]; }; typedef int (*StringFormatFunction)(QTestCharBuffer*,char const*,size_t); /* A wrapper for string functions written to work with a fixed size buffer so they can be called with a dynamically allocated buffer. */ int allocateStringFn(QTestCharBuffer* str, char const* src, StringFormatFunction func) { static const int MAXSIZE = 1024*1024*2; int size = str->size(); int res = 0; for (;;) { res = func(str, src, size); str->data()[size - 1] = '\0'; if (res < size) { // We succeeded or fatally failed break; } // buffer wasn't big enough, try again size *= 2; if (size > MAXSIZE) { break; } if (!str->reset(size)) break; // ran out of memory - bye } return res; } int xmlQuote(QTestCharBuffer* destBuf, char const* src, size_t n) { if (n == 0) return 0; char *dest = destBuf->data(); *dest = 0; if (!src) return 0; char* begin = dest; char* end = dest + n; while (dest < end) { switch (*src) { #define MAP_ENTITY(chr, ent) \ case chr: \ if (dest + sizeof(ent) < end) { \ strcpy(dest, ent); \ dest += sizeof(ent) - 1;\ } \ else { \ *dest = 0; \ return (dest+sizeof(ent)-begin);\ } \ ++src; \ break; MAP_ENTITY('>', ">"); MAP_ENTITY('<', "<"); MAP_ENTITY('\'', "'"); MAP_ENTITY('"', """); MAP_ENTITY('&', "&"); // not strictly necessary, but allows handling of comments without // having to explicitly look for `--' MAP_ENTITY('-', "-"); #undef MAP_ENTITY case 0: *dest = 0; return (dest-begin); default: *dest = *src; ++dest; ++src; break; } } // If we get here, dest was completely filled (dest == end) *(dest-1) = 0; return (dest-begin); } int xmlQuote(QTestCharBuffer* str, char const* src) { return allocateStringFn(str, src, xmlQuote); } void enterTestFunction(const char *function) { QTestCharBuffer quotedFunction; xmlQuote("edFunction, function); } Godbolt link: https://gcc.godbolt.org/z/aPMdYjqEa The warning is In
[Bug middle-end/101134] Bogus -Wstringop-overflow warning about non-existent overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134 --- Comment #2 from Giuseppe D'Angelo --- As I said, > Adding enough __builtin_unreachable() for that condition removes the > warnings, but it should not be necessary. I disagree with the resolution, though. While I understand that GCC cannot reason globally, the warning message itself is miselading, as it's worded in a way that makes the user think that GCC has *conclusevely* proven the existence of a problem, while in fact GCC is wrong. Specifically, this statement: > :75:31: warning: writing 1 byte into a region of size 0 > [-Wstringop-overflow=] At least, I'd like a less strong wording if GCC cannot *prove* this but only estimate it (e.g. "warning: possible string overflow (writing 1 byte...)"). Ideally, even, having two separate warnings or two separate warning levels (overflow proved / overflow just estimated) so one can enable only one of the two if needed.
[Bug c++/100796] [11 Regression] GCC does not honor #pragma diagnostic ignored when using the integrated preprocessor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100796 --- Comment #10 from Giuseppe D'Angelo --- Thank you very much.
[Bug middle-end/101134] Bogus -Wstringop-overflow warning about non-existent overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134 --- Comment #4 from Giuseppe D'Angelo --- Could the warning messages then be changed to point out that the issue is only a mere possibility? Using an "assertive" wording makes users believe that GCC has positively and conclusively proved that there's something wrong, whilst it's exactly the opposite (it didn't prove anything, and it's a false positive). Uninitialized warnings have this distinction and warn in two different ("may be used uninitialized" vs "is used initialized"). If here the distinction cannot be made, AND false positives are allowed to warn, I'd really prefer the "may be overflowing" wording than the "is overflowing" existing one.
[Bug middle-end/101134] Bogus -Wstringop-overflow warning about non-existent overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134 --- Comment #6 from Giuseppe D'Angelo --- (In reply to Martin Sebor from comment #5) > It wouldn't be right to change the wording of just one warning because the > problem applies to all flow based diagnostics. They all depend on various > optimizations that propagate constants, add or remove tests, and change the > control flow graph. A statement that in the source code is conditional on > the values of various parameters might in the intermediate representation > appear unconditional with constants as a result, even be unconditionally > invalid but unreachable. This is true at function scope as well as across > function call boundaries thanks to inlining. Changing the wording for all > of them to try to somehow reflect this wouldn't help because then all > instances of them all would have to use the new form. Sorry, why wouldn't help? That is, given the fact that these warnings do have false positives, why would it bad for such warnings to say "something bad MIGHT be happening here" vs "something bad IS happening here"? For an end user, it makes a lot of difference to know if the compiler has definitely found something wrong vs. the compiler may or may not have found it. Just a tiny language change in the printed mesage would reassure the user that the warning could, in fact, be a false positive. (Compare this to "there IS something bad here". You read the code in question, and you don't see what's bad, and you start digging around trying to understand "why is the compiler telling me that there IS something bad? Am I not seeing something?".) > -Wuninitialized and -Wmaybe-uninitialized aren't substantially different in > this. The latter is unique only in that it diagnoses arguments of PHI > nodes, which are the results of conditional expressions. This property is > described by the following sentence in the manual: > > "...if there exists a path from the function entry to a use of the object > that is initialized, but there exist some other paths for which the object > is not initialized, the compiler emits a warning if it cannot prove the > uninitialized paths are not executed at run time." > > This is only roughly what happens but there are many instances of > -Wuninitialized that could be described using the same sentence, even though > it doesn't consider PHI nodes. If we do introduce a similar distinction in > other warnings like -Wstringop-overflow it will be on top of the instances > already issued by them, not a subset of them. > > This is a general property of all flow based warnings in GCC except those > emitted by the static analyzer which doesn't depend on the same > optimizations (only a very small subset of them). All warnings (flow based > or otherwise, including those issued by the analyzer) should always be > viewed as documented, i.e., as "messages that report constructions that are > not inherently erroneous but that are risky or suggest there may have been > an error." "not inherently erroneous" is as per language rules (i.e. the program isn't ill-formed). But "there may have been" an error is the key I'm trying to point out. The compiler can prove that something is a mistake, or can only estimate that, and so raise a false positive. I'd rather have a message telling me whether a given warning is because of a proof or an estimate.
[Bug middle-end/101134] Bogus -Wstringop-overflow warning about non-existent overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134 --- Comment #8 from Giuseppe D'Angelo --- In a -Wall build, it's a bit unfair to pretend the users to know if a warning is being generated by the frontend, the middleend, the backend and so on. All they get is a list of warnings saying "this is like this, this is like that". You're saying that all such warnings should be treated as "maybe", as false positives are a possibility. But I don't agree with this. First, as I said, the mood of the warning is "indicative", which denotes certainty and reality, not possibility. (But I'll grant, not being a native English speaker, this may just be a personal impression of the warning being "stern".) Second, the presence of things like -Wmaybe-uninitialized vs -Wuninitialized hints at the fact that GCC *wants* to distinguish these "maybe" vs. "certain" cases, at least in certain contexts (like, where it CAN do that!), and give different warnings if it can. Third, frontend warnings simply don't have false positives: if the compiler tells you "this function may be marked override", "this class has virtual functions but no virtual destructor", "this case label falls through into the next one", that's absolutely true in 100% of the cases. A false positive here would clearly be treated as a bug in GCC, and not dismissed as "but it's a warning, and a warning is just a 'maybe', and yes, GCC is telling you to add `override`, and then you added it, and now the program doesn't even build any more because the warning was wrong and `override` was not even needed, but see, it's your fault for not understanding the 'maybe' part". So, in a nutshell, yes, I'd be much more comfortable if warnings that denote a possibility (for any reason, really, I'm not asking to NEVER generate false positives) would simply have "may" or "might" added to their text. If that's the majority of middle-end warnings because they all generate false positives, why would that be a problem, in principle? But fair enough, let's agree to disagree. :)
[Bug middle-end/101134] Bogus -Wstringop-overflow warning about non-existent overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134 --- Comment #13 from Giuseppe D'Angelo --- Hi, (In reply to Martin Sebor from comment #12) > So in general, the distinction between the two cases can only be made when > it can be discerned from the IL, and the IL doesn't always preserve the > conditional nature of the problem statement. So every warning must always > be viewed as a "maybe" kind of a warning. It will never be a sure a thing, > either at the scope of individual functions, and certainly not with inlining > or function cloning. I think there's been a misunderstanding. Apologies if I created confusion, let me try and reset the conversation: I perfectly understand if, in the context of this particular warning (or any other similar middle-end warning), it is very hard, or currently impossible, or even always impossible to distinguish between the "maybe" case and the "certain" case. Without such a distinction available or possible, I'm also OK with raising false positives. Therefore, in relation to this aspect of the original submission (the code raising a false positive warning), I'm perfectly fine at marking the request of not triggering the warning altogether as out of scope / won't fix / etc. On other hand, I was not OK with the idea that the *warning message* should keep saying that "there *is* an overflow", in a positive indicative mood. All I'd really ask there would be to reword the message in order to say something like "there *may be* an overflow" instead. It might seem like a trivial/useless change for someone who knows how the middle-end works and where such warnings come from, but it would bring a lot of clarity to end-users (to me, at least) if any warning message would clearly indicate whether it may be a false positive. And that could be achieved by simply adding "may" to the warning messages in question. Does this make sense? Thanks,
[Bug libstdc++/108846] std::copy, std::copy_n on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 --- Comment #5 from Giuseppe D'Angelo --- > In the case of copy family algorithms, I believe it's OK to specially handle > cases where last - first == 1. https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_algobase.h#L417-L437 Is the extent of the fix just to add another branch to the if (_Num) check here? I've just tried locally, and it seems to work. It also doesn't seem that libstdc++ uses memcpy/memmove elsewhere (e.g. in std::fill).
[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 --- Comment #12 from Giuseppe D'Angelo --- (In reply to Jonathan Wakely from comment #9) > (In reply to Giuseppe D'Angelo from comment #5) > > https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/ > > stl_algobase.h#L417-L437 > > > > Is the extent of the fix just to add another branch to the if (_Num) check > > here? > > Yes, I think that's the simplest place to fix it. > > And we can even get rid of the static assertion, because the Num==1 branch > will require assignability now. > > --- a/libstdc++-v3/include/bits/stl_algobase.h > +++ b/libstdc++-v3/include/bits/stl_algobase.h > @@ -737,16 +737,11 @@ _GLIBCXX_END_NAMESPACE_CONTAINER > static _Tp* > __copy_move_b(const _Tp* __first, const _Tp* __last, _Tp* __result) > { > -#if __cplusplus >= 201103L > - using __assignable = __conditional_t<_IsMove, > - is_move_assignable<_Tp>, > - is_copy_assignable<_Tp>>; > - // trivial types can have deleted assignment > - static_assert( __assignable::value, "type must be assignable" ); > -#endif > const ptrdiff_t _Num = __last - __first; > - if (_Num) > + if (__builtin_expect(_Num > 1, true)) > __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num); > + else if (_Num == 1) > + *__result = *__first; > return __result - _Num; > } > }; If this code path also takes care of std::move(b,e,o), then this doesn't sound correct -- for _Num==1 and _IsMove==true, then it should use a move assignment (std::move(*__first)). But then that std::move doesn't actually work as __first is a pointer to const...
[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 --- Comment #15 from Giuseppe D'Angelo --- That's not what I meant; a type can be trivial(ly copyable) and move-only. Here's a modification of Arthur's example: // move-only struct B { B(int i, short j) : i(i), j(j) {} B(B &&) = default; B &operator=(B &&) = default; int i; short j; }; struct D : B { D(int i, short j, short x) : B(i, j), x(x) {} D(D &&) = default; D &operator=(D &&) = default; short x; }; int main() { D ddst(1, 2, 3); D dsrc(4, 5, 6); B *dst = &ddst; B *src = &dsrc; static_assert(std::is_trivially_copyable_v); std::move(src, src+1, dst); assert(ddst.x == 3); } The call to std::move ends up in the same memmove codepath as std::copy_n (B is trivially copyable), but with the proposed patch it will fail to compile because it's not actually copy assignable.
[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 --- Comment #20 from Giuseppe D'Angelo --- Thanks for the patch! Should ranges_algobase.h also be similarly changed? There's a memmove in its copy/move code as well: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/ranges_algobase.h;hb=HEAD#l263
[Bug libstdc++/102221] Missed optimizations for algorithms over std::unique_ptr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102221 --- Comment #6 from Giuseppe D'Angelo --- Hi, (Sorry for chiming in after all this time); given this might not entirely be libstdc++ related (cf. the latest testcase), would it be possible for someone on the optimizer to gave their opinion?
[Bug c++/102396] [11/12 Regression] ICE when using concepts, in get, at cp/constraint.cc:2637 since r11-6245-g79f57d5cb070bb02
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102396 --- Comment #3 from Giuseppe D'Angelo --- Hello Patrick, Thank you for the insights. I'm left wondering however if the CWG resolution would possibly ever allow the operator== to be defined as a hidden friend; the workaround you mentioned may lead to redefinition errors (as now it doesn't depend on S any more)?
[Bug c++/102396] [11/12 Regression] ICE when using concepts, in get, at cp/constraint.cc:2637 since r11-6245-g79f57d5cb070bb02
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102396 --- Comment #4 from Giuseppe D'Angelo --- To elaborate on the last comment, this testcase does complain about the redefinition. #include #include template class S; template static inline std::true_type is_S_impl(const S&); static inline std::false_type is_S_impl(...); template concept is_S = decltype(is_S_impl(std::declval()))::value; template struct S { using type = T; T data; S(); explicit S(const T &); template requires is_S && (!is_S) && std::equality_comparable_with friend bool operator==(const V &v, const U &u) { return v.data == u; } }; void f() { S s1; s1 == 123; S s2; s2 == 123.4; }
[Bug c++/102396] [11/12 Regression] ICE when using concepts, in get, at cp/constraint.cc:2637 since r11-6245-g79f57d5cb070bb02
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102396 --- Comment #6 from Giuseppe D'Angelo --- That's brilliant! I really hadn't thought that pushing the hidden friend into a private base would work nonetheless. Thanks!
[Bug c++/102221] New: Missed optimizations for algorithms over std::unique_ptr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102221 Bug ID: 102221 Summary: Missed optimizations for algorithms over std::unique_ptr Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Sorting/heaping/etc. an array/vector of unique_ptr generates worse codegen than the equivalent code on an array of raw pointers. This is a missed optimization, as the operations involved should just be mere swaps. For instance: #include #include #if defined(SMART) using ptr = std::unique_ptr; #else using ptr = int*; #endif void f() { extern ptr *data; const auto cmp = [](const auto &a, const auto &b) { return *a < *b; }; std::sort(data, data+1000, cmp); } https://gcc.godbolt.org/z/7zPYxr9q7 This generates quite some extra code (including calls to operator delete); the result is that such a sort is slower than the countepart with a raw pointer.
[Bug libstdc++/102221] Missed optimizations for algorithms over std::unique_ptr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102221 --- Comment #2 from Giuseppe D'Angelo --- Hi, Thanks for the analysis! That basically allows me to reduce the testcase to something as simple as a swap: #include #include #if defined(SMART) using ptr = std::unique_ptr; #else using ptr = int *; #endif auto swap1(ptr &a, ptr &b) { if (&a == &b) __builtin_unreachable(); // ptr tmp(std::move(a)); a = std::move(b); b = std::move(tmp); } auto swap2(ptr &a, ptr &b) { // deliberate std::swap(a, b); } https://gcc.godbolt.org/z/Tqzz5eqrW In both cases there's basically a call to "delete nullptr" that doesn't get removed. I don't think this falls on libstdc++, rather than on the optimizer?
[Bug libstdc++/102221] Missed optimizations for algorithms over std::unique_ptr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102221 --- Comment #5 from Giuseppe D'Angelo --- Here's a further testcase that doesn't even use unique_ptr: #include #include using ptr = int *; using rawptr = int *; #ifndef RESTRICT #define RESTRICT #endif void swap(ptr & RESTRICT a, ptr & RESTRICT b) { if (std::addressof(a) == std::addressof(b)) __builtin_unreachable(); ptr tmp = a; a = nullptr; // ptr tmp = std::move(a) // a = std::move(b) #if ONE { // a.reset(b.release()) rawptr tmp = b; // b.release() b = nullptr; rawptr old = a; // a.reset(tmp) a = tmp; delete old; } #elif TWO { // move+swap rawptr tmp = b; b = nullptr; // ptr tmp = std::move(b) { // a.swap(tmp) rawptr tmp2 = a; a = tmp; tmp = tmp2; } // ~tmp delete tmp; } #elif THREE { delete a; a = b; b = nullptr; } #else #error #endif delete b; b = tmp; tmp = nullptr; // b = std::move(tmp) delete tmp; } https://gcc.godbolt.org/z/bv1T64ndo ONE and TWO don't elide the delete, unless the arguments are marked __restrict__. THREE does elide it. Sounds like some escape analysis going wrong, combined with unique_ptr's self-move-assignment safety (that "bans" THREE's implementation).
[Bug c++/102283] New: Inconsistent/wrong overload resolution when using an initializer list and a defaulted template parameter
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102283 Bug ID: 102283 Summary: Inconsistent/wrong overload resolution when using an initializer list and a defaulted template parameter Product: gcc Version: 11.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hello, The following testcase has an "inconsistent" overload resolution: template struct helper {}; struct data {}; template struct S { template void f(T2 &&); // #1 template void f(const helper &); // #2 }; int main() { S s1; S s2; s1.f({}); s2.f({}); } https://gcc.godbolt.org/z/nsj48M7af On GCC 11, the the first call to f() resolves to #1, but the second call resolves to #2. I cannot find any reason for this inconsistency in the ranking of the overloads; no warnings are emitted under -Wall -Wextra. Clang and MSVC both always call #1.
[Bug c++/102283] Inconsistent/wrong overload resolution when using an initializer list and a defaulted template parameter
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102283 --- Comment #2 from Giuseppe D'Angelo --- Hi, Do you think that in my original testcase the call should be rejected as ambiguous as well? (It seems "reasonable" to me, but maybe I'm missing some niche detail about overload resolution when combined with template deduction.) This small variation over the testcase: struct A { }; struct B { }; template void f(T &&); // #1 void f(const B&) = delete; // #2 int main() { f({}); } This now makes GCC select #2, and fail to compile because it's deleted; Clang and MSVC still select #1. But a further, minor change: struct A { }; struct B { }; template // <-- changed this void f(T &&); // #1 void f(const B&) = delete; // #2 int main() { f({}); } makes GCC select #1...
[Bug c++/102396] New: ICE when using concepts, in get, at cp/constraint.cc:2637
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102396 Bug ID: 102396 Summary: ICE when using concepts, in get, at cp/constraint.cc:2637 Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hello, This testcase (which gets accepted by Clang and MSVC) causes an ICE under GCC-12-trunk, and an erroneous compilation error on GCC 11.2. #include #include #include #include template struct S; template constexpr bool is_S = false; template constexpr bool is_S> = true; template struct S { T data; S(); explicit S(const T &); template , bool> = false> requires std::equality_comparable_with friend bool operator==(const S &s, const U &u) { return s.data == u; } }; template bool operator==(const S &a, const S &b) { return a.data == b.data; } int main() { using SD = S; char data[sizeof(SD) * 10]; std::span span((SD*)std::begin(data), (SD*)std::end(data)); //static_assert(std::equality_comparable::iterator>); std::ranges::uninitialized_default_construct(span); } The error: /opt/compiler-explorer/gcc-trunk-20210918/include/c++/12.0.0/concepts:280:17: internal compiler error: in get, at cp/constraint.cc:2637 280 | { __t == __u } -> __boolean_testable; | ^~ 0x1fc77b9 internal_error(char const*, ...) ???:0 0x713d19 fancy_abort(char const*, int, char const*) ???:0 0x7970af satisfaction_cache::get() ???:0 0x79cd8a constraints_satisfied_p(tree_node*, tree_node*) ???:0 0x9ba323 fn_type_unification(tree_node*, tree_node*, tree_node*, tree_node* const*, unsigned int, tree_node*, unification_kind_t, int, conversion**, bool, bool) ???:0 0x73f150 build_new_op(op_location_t const&, tree_code, int, tree_node*, tree_node*, tree_node*, tree_node**, int) ???:0 0xa2fc50 build_x_binary_op(op_location_t const&, tree_code, tree_node*, tree_code, tree_node*, tree_code, tree_node**, int) ???:0 0x79cd42 tsubst_requires_expr(tree_node*, tree_node*, int, tree_node*) ???:0 0x79cd8a constraints_satisfied_p(tree_node*, tree_node*) ???:0 0x9ba323 fn_type_unification(tree_node*, tree_node*, tree_node*, tree_node* const*, unsigned int, tree_node*, unification_kind_t, int, conversion**, bool, bool) ???:0 0x73f150 build_new_op(op_location_t const&, tree_code, int, tree_node*, tree_node*, tree_node*, tree_node**, int) ???:0 0xa2fc50 build_x_binary_op(op_location_t const&, tree_code, tree_node*, tree_code, tree_node*, tree_code, tree_node**, int) ???:0 0x9816d7 instantiate_decl(tree_node*, bool, bool) ???:0 0x9c3e1b instantiate_pending_templates(int) ???:0 0x82a899 c_parse_final_cleanups() ???:0
[Bug c++/102397] New: Documentation of attribute syntax does not discuss C++11 / C23 attribute syntax
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102397 Bug ID: 102397 Summary: Documentation of attribute syntax does not discuss C++11 / C23 attribute syntax Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, The available documentation for attributes syntax https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax does not mention at all the possibility that in C++11 (and, I imagine, in C23) one can specify any GCC-specific attribute using a [[gnu::attribute]] attribute specifier, and not only the GCC-specific __attribute__((attribute)) syntax. I think it would be worth mentioning in there that this is actually OK and fully supported.
[Bug c++/102399] New: Cannot mix GCC and C++11 / C23 attribute syntax
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102399 Bug ID: 102399 Summary: Cannot mix GCC and C++11 / C23 attribute syntax Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hello, If one tries to mix GCC's attribute syntax (__attribute__) and with C++11 / C23 ([[attribute]]), GCC rejects the code (no matter what the order of the attributes is): #define EXPORT __attribute__((visibility("default"))) struct [[nodiscard]] EXPORT Foo { Foo(); }; https://gcc.godbolt.org/z/W868xjeMq While a workaround exists (by sticking to the same "kind" of attribute syntax), it's not always possible or easy to achieve in big codebases, where for compatibility/legacy reasons the attributes are expanded via macros and can expand to a random combination of GCC or C++ attributes. For comparison, Clang and MSVC allow mixed syntaxes.
[Bug c++/102283] Inconsistent/wrong overload resolution when using an initializer list and a defaulted template parameter
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102283 --- Comment #5 from Giuseppe D'Angelo --- (Sorry for the delay) Thank you for the analysis. I'm now not really sure if GCC is doing something wrong (vs Clang/MSVC). Feel free to close/suspend this task if you strongly believe GCC is right here.
[Bug c++/107495] New: GCC does not consider the right contextual implicit conversions
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107495 Bug ID: 107495 Summary: GCC does not consider the right contextual implicit conversions Product: gcc Version: 12.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Testcase: struct Test { operator int *() const; operator void *() const; }; int main() { Test t; delete t; } GCC rejects this: : In function 'int main()': :32:12: error: ambiguous default type conversion from 'Test' 32 | delete t; |^ :32:12: note: candidate conversions include 'Test::operator void*() const' and 'Test::operator int*() const' :32:12: error: type 'struct Test' argument given to 'delete', expected pointer But this is wrong. https://eel.is/c++draft/expr.delete#1.sentence-5 says "If of class type, the operand is contextually implicitly converted to a pointer to object type" and the attached note explicitly says "This implies that an object cannot be deleted using a pointer of type void* because void is not an object type". The definition of contextual conversion says https://eel.is/c++draft/conv#general-5 : "C is searched for non-explicit conversion functions whose return type is cv T or reference to cv T such that T is allowed by the context. There shall be exactly one such T." There is exactly one such T (conversion to pointer of object type), so GCC is rejecting valid code.
[Bug c++/107495] GCC does not consider the right contextual implicit conversions
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107495 --- Comment #1 from Giuseppe D'Angelo --- Variation of the above: struct Test { template operator int *() const; }; Test t; delete t; also fails: : In function 'int main()': :32:12: error: default type conversion cannot deduce template argument for 'template Test::operator int*() const' 32 | delete t; |^ :32:12: error: type 'struct Test' argument given to 'delete', expected pointer But here I'm not 100% sure; is there is supposed to be any template argument deduction? Clang rejects this as well, while MSVC accepts it.
[Bug c++/107507] New: Conversion function templates are not sometimes not considered if the return type is type dependent
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107507 Bug ID: 107507 Summary: Conversion function templates are not sometimes not considered if the return type is type dependent Product: gcc Version: 12.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Testcase: template struct Test { template operator T(); }; int main() { Test t; int *x = t; // OK int *y = t + 42; // ERROR } : In function 'int main()': :20:16: error: no match for 'operator+' (operand types are 'Test' and 'int') 228 | int *y = t + 42; | ~ ^ ~~ | | | | | int | Test This seems to depend on whether the conversion operators themselves are function templates that return a type dependend on T. For instance, this works: template struct Test { template operator int *(); // don't return a type that depends on T }; int main() { Test t; int *x = t; int *y = t + 42; // OK } And also this works: template struct Test { operator T(); // not a template }; int main() { Test t; int *x = t; int *y = t + 42; } I see that conversion function templates are treated in a special way in a couple of places in the Standard but I'm not sure -- e.g. does https://eel.is/c++draft/over.ics.user#3 apply here?. For comparison, Clang also rejects this, while MSVC (in C++latest mode) accepts it.
[Bug libstdc++/107525] New: propagate_const should not be using SFINAE on its conversion operators
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107525 Bug ID: 107525 Summary: propagate_const should not be using SFINAE on its conversion operators Product: gcc Version: 12.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- propagate_const in the LFTSv3 has implicit conversion operators which have constraints on them: https://cplusplus.github.io/fundamentals-ts/v3.html#propagate_const.const_observers > constexpr operator const element_type*() const; > > Constraints: >T is an object pointer type or has an implicit conversion to const > element_type*. > Returns: >get(). libstdc++ implements these constraints by means of SFINAE on the operators. This is user-hostile: using SFINAE means that the conversion operator is now a function template, and that means that https://eel.is/c++draft/over.ics.user#3 kicks in: > If the user-defined conversion is specified by a specialization of a > conversion function template, the second standard conversion sequence shall > have exact match rank. Concretely, this means that for instance we lose implicit conversions towards base classes of the pointed-to type: std::experimental::propagate_const ptr; Derived *d1 = ptr; // Convert precisely to Derived *: OK Base *b1= ptr; // Convert to a pointer to a base: ERROR Base *b2= static_cast(ptr); // OK Base *b3= static_cast(ptr);// ERROR Base *b4= ptr.get(); // OK But these should all work. The design of propagate_const is for it to be "drop-in replacement", maximizing compatibility with existing code. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html says explictly "When T is an object pointer type operator value* exists and allows implicit conversion to a pointer. This avoids using get to access the pointer in contexts where it was unnecesary before addition of the propagate_const wrapper." -- So. ideally, the conversion operators should be using C++20 constraints, but of course that's not possible. I guess that a reasonable alternative would be to isolate them in a base class, and apply SFINAE on that base class instead?
[Bug libstdc++/107525] propagate_const should not be using SFINAE on its conversion operators
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107525 --- Comment #4 from Giuseppe D'Angelo --- (In reply to Jonathan Wakely from comment #1) > (In reply to Giuseppe D'Angelo from comment #0) > > So. ideally, the conversion operators should be using C++20 constraints, but > > of course that's not possible. > > It's totally possible for C++20 mode. > > I don't know how much motivation anybody has to do anything about this > though. Sorry, what I meant is, of course there is interest at keeping this code to compile in pre-C++20 mode, and possibly have the same semantics no matter what's the language version used? Or is it acceptable to have such an "API break"? (E.g. stuff like `is_convertible_v, Base *>` changes value.) > And the spec seems wrong as well. The const overload should be constrained > for const T being convertible to const element_type*. Yes, that sounds like a defect to me. -- More in general, I think these operators are strangely defined. I'm not sure why they're not simply defined to be template operator U *() requires (std::is_convertible_v); mut.mut. for the `const` version. The current definition also allows for pointer arithmetic (only if one uses a C++20 constraint, otherwise it doesn't work), which is something the original paper says it does NOT want to support. And the current definition allows for `delete`ing a propagate_const, which maybe is wanted, but in contradiction with the lack of support for pointer arithmetic. I guess I'll need to submit a paper.
[Bug libstdc++/107525] propagate_const should not be using SFINAE on its conversion operators
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107525 --- Comment #9 from Giuseppe D'Angelo --- (In reply to Jonathan Wakely from comment #5) > Please don't! At least not in the next 9 days. We intend to vote out LFTSv3 > at next week's meeting, there will be no more proposals for LFTS considered. > And I don't want to derail the vote next week by having open proposals > arriving at the last minute. No problem, I wouldn't have done this before a few weeks anyhow. > Feel free to file a library issue though. If propagate_const ever gets > proposed for inclusion in the standard then this should be taken into > account. OK. Thank you very much for the prompt fix. (Ville: guess what, this bug stem from trying to make uic and friends use propagate_const. Small world!)
[Bug c++/107697] New: -Wredundant-move misses std::move applied to const objects (instead of const references)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107697 Bug ID: 107697 Summary: -Wredundant-move misses std::move applied to const objects (instead of const references) Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, Consider this testcase: #include using T = std::vector; void f(T); void use1(const T t) { f(std::move(t)); } void use2(const T &t) { f(std::move(t)); } void use3() { const T t; f(std::move(t)); } Currently -Wredundant-move warns only for case 2. But in all three cases std::move is actually not doing anything good (copy constructor is always selected). It would be nice if they all were diagnosed. If I change `f` to `void f(const T &)` then there's no warning at all. I'm thinking that probably this case should be diagnosed as well. Clang-tidy's performance-move-const-arg diagnoses them all.
[Bug c++/99625] GCC does not detect narrowing in aggregate initialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99625 --- Comment #3 from Giuseppe D'Angelo --- Hi, Sorry to ping, but some time has gone by -- I guess this fell through the cracks?
[Bug c++/99625] GCC does not detect narrowing in aggregate initialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99625 --- Comment #5 from Giuseppe D'Angelo --- No problem, thanks for working on GCC :)
[Bug libstdc++/113060] std::variant converting constructor/assignment is non-conforming after P2280?
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113060 --- Comment #7 from Giuseppe D'Angelo --- Hi, > Note that this example adds a mediate function template > (test_array_element_initializable) to "reduce" the non-constexpr-ness of > std::declval. That's very clever, thank you! Is it _supposed_ to work, though? I had imagined (possibly erroneusly) that once one places the call to `test_array_element_initializable` using `declval` as an argument, it would disqualify the whole thing from being usable in constant expressions. (It would help to have another compiler that implements P2280, so to do more tests...)
[Bug libstdc++/113060] std::variant converting constructor/assignment is non-conforming after P2280?
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113060 --- Comment #9 from Giuseppe D'Angelo --- Thank you, I'll amend P3146 with this new information, and try and make sure that LEWG/LWG see the updated draft (if they discuss this before the next mailing).
[Bug middle-end/114029] New: -Warray-bounds does not warn for global arrays
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114029 Bug ID: 114029 Summary: -Warray-bounds does not warn for global arrays Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Testcase https://gcc.godbolt.org/z/n3zPPE7bq const int test[]={1, 2, 3}; int main() { return test[3]; } GCC doesn't warn under -O2 -Wall. It does emit a -Warray-bounds warning if the `test` array is moved inside `main`; but why not warning for a global variable? For comparison, Clang always warns (even without any optimization/warning flag).
[Bug libstdc++/116471] New: Strange/bogus static_assert in ranges::copy / move algorithms
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116471 Bug ID: 116471 Summary: Strange/bogus static_assert in ranges::copy / move algorithms Product: gcc Version: 14.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, This code fails to build on GCC 14 (CE link: https://gcc.godbolt.org/z/qnYGd48Ko ) #include struct X { X& operator=(X&) = default; // non-const }; int main() { extern X *b, *e, *out; std::ranges::copy(b, e, out); } /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/ranges_algobase.h:259:23: error: static assertion failed 258 | static_assert(_IsMove | ~~~ 259 | ? is_move_assignable_v<_ValueTypeI> | ^~~ 260 | : is_copy_assignable_v<_ValueTypeI>); | ~~~ /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/ranges_algobase.h:259:23: note: '(false ? std::is_move_assignable_v : std::is_copy_assignable_v)' evaluates to false Indeed X fails is_copy_assignable because its copy assignment operator takes by non-const reference. It's not entirely clear why that static_assert is there, given that ranges::copy/move algorithms are already constrained on concepts (like indirectly_copyable). It's also worth noting that the static_assert is into a if constexpr( __memcpyable<_Iter, _Out>::__value) branch. memcpyable basically means trivially copyable (except for pointers to volatile), however trivially copyable does NOT imply is_copy_assignable (because it just checks that eligible copy assignments are trivial, not that they work from a `const T`). I can send a patch, but I'm not sure in which direction this should go. I stumbled upon this while extending the fix PR108846 to range algorithms.
[Bug libstdc++/116471] Strange/bogus static_assert in ranges::copy / move algorithms
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116471 --- Comment #3 from Giuseppe D'Angelo --- > You might be right that we never needed it in ranges::copy because it's > already constrained correctly. So would it be OK to just remove the static_assert from the range-based algorithms? > N.B. That's not quite accurate, which is why we needed the check in std::copy. > A type with deleted assignment operators can also be trivially copyable. I think I worded myself poorly, what I meant to say is that the check *is* checking something, precisely because is_copy_assignable is not implied by __memcpyable. In other words, the check wasn't "useless".
[Bug libstdc++/116471] Strange/bogus static_assert in ranges::copy / move algorithms
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116471 --- Comment #4 from Giuseppe D'Angelo --- Created attachment 58984 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58984&action=edit patch v1 Attaching a patch for this + PR108846 , since the testcases basically cover both in one go.
[Bug libstdc++/116471] Strange/bogus static_assert in ranges::copy / move algorithms
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116471 Giuseppe D'Angelo changed: What|Removed |Added Attachment #58984|0 |1 is obsolete|| --- Comment #6 from Giuseppe D'Angelo --- Created attachment 58985 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58985&action=edit patch v2 Better patch, that makes use of __assign_one in a few more places.
[Bug c++/114764] New: noexcept on a friend complains about incomplete type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114764 Bug ID: 114764 Summary: noexcept on a friend complains about incomplete type Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Testcase: struct S { S(int) noexcept; void f() noexcept(noexcept(S(42))); friend void g() noexcept(noexcept(S(42))); }; https://godbolt.org/z/qn5Gs4M63 GCC 14 trunk rejects with: :6:43: error: invalid use of incomplete type 'struct S' 6 | friend void g() noexcept(noexcept(S(42))); | ^ :1:8: note: definition of 'struct S' is not complete until the closing brace 1 | struct S |^ Compiler returned: 1 But that does not seem to be accurate: https://eel.is/c++draft/class.mem.general#7 says "A complete-class context of a class (template) is a [...] noexcept-specifier ([except.spec]) [...] within the member-specification of the class or class template." and a friend declaration/definition is a member-specification. This is possibly related to bug 70077. For comparison Clang rejects, but MSVC accepts.
[Bug c++/114764] noexcept on a friend complains about incomplete type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114764 --- Comment #3 from Giuseppe D'Angelo --- I guess you're referring to https://lists.isocpp.org/core/2019/07/6785.php ? I'm really not sure why a friend function declaration is different from a free function, where multiple equivalent declarations are allowed? Btw, the "real" case was a definition of a friend (hidden friend). Could at least that be supported?
[Bug c++/114764] noexcept on a friend complains about incomplete type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114764 --- Comment #5 from Giuseppe D'Angelo --- Just to understand, are we talking about an implementation challenge (because within a class you may refer to stuff not yet declared when parsing the noexcept spec, or similar), or that using noexcept on a friend "doesn't make sense"?
[Bug c++/114764] noexcept on a friend complains about incomplete type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114764 --- Comment #7 from Giuseppe D'Angelo --- I get it :) If you wanted an actual use-case (rather than a synthetic testcase), we stumbled upon this bug from implementing a friend operator==: ``` class S { bool comparesEqual(S, S) noexcept; // pass by value, object is small/trivially copyable friend inline bool operator==(S a, S b) noexcept(noexcept(comparesEqual(S, S))) { returns comparesEqual(a, b); } }; ``` which is the result of some macro expansions through which we support C++20's comparisons in C++17 in Qt. The problem is the pass by value -- changing it to pass by const-ref fixes it, but generates different linting about not passing a small TC object by value...
[Bug c++/112477] New: Assignment of value-initialized iterators differs from value-initialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112477 Bug ID: 112477 Summary: Assignment of value-initialized iterators differs from value-initialization Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- In debug mode there seems to be a difference between a value-initialized iterator, and an iterator that gets assigned from a value-initialized iterator. Testcase: https://gcc.godbolt.org/z/hW7d7Pao3 #define _GLIBCXX_DEBUG #include int main() { using M = std::map; using I = M::iterator; M map{ {1, 1}, {2, 2} }; I it1 = map.begin(); it1 = I{}; I it2{}; (void)(it1 == it2); } Results in Error: attempt to compare a singular iterator to a singular (value-initialized) iterator. It's not entirely clear to me why this shouldn't "just work™", although this is probably threading the needle; assignment *from* a singular iterator isn't really discussed in https://eel.is/c++draft/iterator.requirements.general#7 nor in https://eel.is/c++draft/forward.iterators#2 . (One may argue that this last sentence was added by N3644, when iterators still required copiability, so copying a value-constructed iterator should have value semantics and the result be indistinguishable from value-initializing...)
[Bug libstdc++/112477] Assignment of value-initialized iterators differs from value-initialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112477 Giuseppe D'Angelo changed: What|Removed |Added Component|c++ |libstdc++ --- Comment #1 from Giuseppe D'Angelo --- Sorry, I've accidentally selected the wrong component.
[Bug tree-optimization/112637] New: Bogus -Wmaybe-uninitialized warning
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112637 Bug ID: 112637 Summary: Bogus -Wmaybe-uninitialized warning Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Testcase from Qt: https://gcc.godbolt.org/z/6brn9Knra class QBenchmarkIterationController { public: QBenchmarkIterationController() noexcept; bool isDone() const noexcept; void next() noexcept; }; class QBenchmarkIterationControllerWrapper { QBenchmarkIterationController controller; bool first = true; public: QBenchmarkIterationControllerWrapper() = default; bool isDone() const noexcept { return !first && controller.isDone(); } void next() noexcept { first = false; controller.next(); } }; int f() noexcept; void check(bool); void testcase() { int result; for (QBenchmarkIterationControllerWrapper w; !w.isDone(); w.next()) result = f(); check(result == 42); } With warnings enabled and any level of optimization enabled, results in: : In function 'void testcase()': :31:10: warning: 'result' may be used uninitialized [-Wmaybe-uninitialized] 31 | check(result == 42); | ~^~ :26:9: note: 'result' was declared here 26 | int result; | ^~ But this is bogus, as the loop is always entered at least once. Removing the declaration of QBenchmarkIterationController's constructor makes the warning disappear. Upstream Qt patch discussion: https://codereview.qt-project.org/c/qt/qtbase/+/518574
[Bug middle-end/110375] New: -ftrivial-auto-var-init=zero issues with pointers to data members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110375 Bug ID: 110375 Summary: -ftrivial-auto-var-init=zero issues with pointers to data members Product: gcc Version: 13.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- -ftrivial-auto-var-init=zero is documented to "Initialize automatic variables with zeroes". I assume that means to memset(0) their storage. 0 is a bit pattern that works _almost_ universally to set a "safe" default. However, pointers to data members are a problem: on Itanium, a null pointer to data member is represented by -1u, and not 0. https://itanium-cxx-abi.github.io/cxx-abi/abi.html#data-member-pointers This means that this snippet hits the assert under -ftrivial-auto-var-init=zero: #include struct S {}; int main() { int S::*ptr; assert(ptr == nullptr); } https://gcc.godbolt.org/z/7sb6GcbPE IMHO it would be more useful to have -ftrivial-auto-var-init=zero to mean "to _value-initialize_ automatic variables", including non-static data members of classes, recursively, before a constructor is eventually run. Such value-initialization for scalar taypes resolves into zero-initialization (and *not* zero-filling), as per https://eel.is/c++draft/dcl.init#general-9.3 , so the name "=zero" is still somehow appropriate. The difference is that zero-initialization will correctly sets *all* pointers types to null.
[Bug middle-end/110375] -ftrivial-auto-var-init=zero issues with pointers to data members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110375 --- Comment #2 from Giuseppe D'Angelo --- (In reply to Andrew Pinski from comment #1) > The code is undefined, Sure, although there are C++ proposals to make it well-defined / implementatiopn-defined (see https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2723r1.html and https://isocpp.org/files/papers/P2795R1.html). But that's beside the point, I'm not claiming that the code does not have UB -- although I'm not sure whether, if -ftrivial-auto-var-init is in use, an optimizer stops considering such reads as UB. At least Clang stops: https://gcc.godbolt.org/z/bKW5Mccsa > the point to initialize it something which might be > safe enough for most cases. Yes in the case of pointer to data members, it > is not the same as null but that is ok, it is still intialized to something. What I'm asking is to make it safe for *more* cases, so I don't see what's wrong with such a feature request. -ftrivial-auto-var-init has several options precisely because one may want different bit patterns of initialization for various purposes (safety/ease of debugging/...); right now it's just * all 0 (=zero) * all 0xFE (=pattern) Something that zero-initializes is missing, and I'm asking to make =zero do so. -- Anyhow, this is useful information, because P2795R1 claims its proposed behavior is already implemented by GCC, while it actually isn't. It also isn't by Clang (twin bug report https://github.com/llvm/llvm-project/issues/63471 ).
[Bug middle-end/110375] -ftrivial-auto-var-init=zero issues with pointers to data members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110375 --- Comment #4 from Giuseppe D'Angelo --- (In reply to Andrew Pinski from comment #3) > (In reply to Giuseppe D'Angelo from comment #2) > > (In reply to Andrew Pinski from comment #1) > > > The code is undefined, > > > > Sure, although there are C++ proposals to make it well-defined / > > implementatiopn-defined (see > > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2723r1.html and > > https://isocpp.org/files/papers/P2795R1.html). > > > > But that's beside the point, I'm not claiming that the code does not have UB > > -- although I'm not sure whether, if -ftrivial-auto-var-init is in use, an > > optimizer stops considering such reads as UB. At least Clang stops: > > https://gcc.godbolt.org/z/bKW5Mccsa > > But those proposals will be done in the front-end That's not P2723R1's claim. Quoting: "We propose to zero-initialize all objects of automatic storage duration, making C++ safer by default. This was implemented as an opt-in compiler flag in 2018 for LLVM [LLVMReview] and MSVC [WinKernel], and 2021 in for GCC [GCCReview]." This report (and Clang's) shows that that's misleading. > while > -ftrivial-auto-var-init=zero is a generic non-front-end option. The > middle-end will see the right thing and that option will not have an effect > really. Fair enough; then, please, could this report be turned into a feature request for the C/C++ frontends?
[Bug c++/110404] New: Feature request: make -ftrivial-auto-var-init=zero zero-initialize, not zero-fill
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110404 Bug ID: 110404 Summary: Feature request: make -ftrivial-auto-var-init=zero zero-initialize, not zero-fill Product: gcc Version: 13.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hello, This is the same report as bug 110375, however turned into a wishlist/feature request for the C++ front-end. Right now -ftrivial-auto-var-init=zero is a middle-end feature that zero-fills storage for automatic variables. 0x00 is a bit pattern that works _almost_ universally to set a "safe" default. However, pointers to data members are a problem: on Itanium, a null pointer to data member is represented by -1u, and not 0. https://itanium-cxx-abi.github.io/cxx-abi/abi.html#data-member-pointers This means that this snippet hits the assert under -ftrivial-auto-var-init=zero: #include struct S {}; int main() { int S::*ptr; assert(ptr == nullptr); } https://gcc.godbolt.org/z/7sb6GcbPE IMHO it would be more useful to have -ftrivial-auto-var-init=zero to mean "to _value-initialize_ automatic variables" (and zero-fill padding bits), including non-static data members of classes, recursively, before a constructor is eventually run. Such value-initialization for scalar types resolves into zero-initialization (and *not* zero-filling), as per https://eel.is/c++draft/dcl.init#general-9.3 , so the name "=zero" is still somehow appropriate. The difference is that zero-initialization will correctly sets *all* pointers types to null. -- Regarding whether one should change -ftrivial-auto-var-init=zero semantics or introduce a new command line option, I'd rather change the semantics. The fact that it's currently a middle-end feature is not interesting at all for the end-user. In their mind, what they want is zero-initialization, not zero-filling (aka any sort of pointer is nullptr, any arithmetic is 0, etc; irregardless of ABI). For the C front-end, this shouldn't mean any change (unless GCC runs on some C ABI where pointers or floating pointes aren't all 0-bits?). For the C++ front-end, this means fixing pointers to data members Itanium. -- References: * https://github.com/llvm/llvm-project/issues/63471 twin bug report * https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2723r1.html that aims to zero-initialize variables with automatic storage, but erronousely say that GCC and Clang already implement this feature.
[Bug middle-end/110375] -ftrivial-auto-var-init=zero issues with pointers to data members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110375 --- Comment #5 from Giuseppe D'Angelo --- Done in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110404 .
[Bug c++/110404] Feature request: add a new option which is like -ftrivial-auto-var-init=zero but zero-initialize instead of zero-fill
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110404 --- Comment #2 from Giuseppe D'Angelo --- (In reply to Richard Biener from comment #1) > But your testcase is invoking undefined behavior when inspecting 'ptr'? > That doesn't change with -ftrivial-auto-var-init=zero, so getting a trap is > good > here and you need to fix your code instead. Hi, Well, the point of -ftrivial-auto-var-init=zero is to turn that UB in a specific behavior, that is, to read 0. From a formal point of view, this is a perfectly valid expression of UB. The problem I'm raising above is that I'd like reads of uninitialized pointers to yield nullptr, which is currently not the case of pointers to data members on Itanium. -- Then there's the question regarding whether GCC can "see the UB" and e.g. optimize the whole thing away, based on reasonings like "this code exhibits UB, therefore it can never be called, therefore it's dead, therefore I can remove it". I don't know if this is actually the case at the moment, but if it is, I'd consider it a *different* bug report. The whole point of -ftrivial-auto-var-init=zero is to prevent that sort of UB from manifesting itself (by zero-filling the storage); to prevent leaking "secrets" (leaks that imply an uninitialized read anyhow, so UB); etc. I am not able at the moment to prove or disprove this using GCC. Clang however disables such UB-optimizations when using -ftrivial-auto-var-init=zero : https://gcc.godbolt.org/z/qhMxM11jE
[Bug libstdc++/58338] Add noexcept to functions with a narrow contract
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58338 Giuseppe D'Angelo changed: What|Removed |Added CC||dangelog at gmail dot com --- Comment #17 from Giuseppe D'Angelo --- Hi, How does all of this intersect with the Lakos' Rule (cf. the very recent P2837 and P2861)? I get that implementations have the freedom of strenghtening the noexcept contract; but is this patch following some specific libstdc++ policy (documented somewhere) -- such as, if a precondition violation is detected, libstdc++ just abort()s the process, so technically speaking, it never throws?
[Bug libstdc++/113060] New: std::variant converting constructor/assignment is non-conforming after P2280?
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113060 Bug ID: 113060 Summary: std::variant converting constructor/assignment is non-conforming after P2280? Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- GCC 14 implements P2280 (see #106650). As a side effect of that, the "narrowing detector" used in std::variant's converting constructor/assignment is now too restrictive. This code: // IC is a type with a constexpr conversion operator using IC = std::integral_constant; std::variant v( IC{} ); should work after P2280 (libstdc++ says ill-formed). --- https://eel.is/c++draft/variant.ctor#14 says: > Let Tj be a type that is determined as follows: build an imaginary function > FUN(Ti) for each alternative type Ti for which Ti x[] = > {std::forward(t)}; is well-formed for some invented variable x. > The overload FUN(Tj) selected by overload resolution for the expression > FUN(std::forward(t)) defines the alternative Tj which is the type of > the contained value after construction. Right now libstdc++ implements this by means of SFINAE: > https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/variant#L787-L823 IC is convertible to float, and given the constexpr nature of its conversion operator (to int), it wouldn't be a narrowing conversion: IC ic; float f{ic}; // not narrowing However, using SFINAE means that std::declval() is used to build the "candidate" argument of FUN. declval is not a constexpr function so its returned value is not considered to be usable in constant expressions. The net effect is that `Ti x[] = {std::forward(t)};` is considered to be a narrowing conversion ([dcl.init.list], int->float, source is not a constant expression), and FUN(float) rejected. But nowhere does [variant.ctor] talk about using std::declval; if one reimplements the same check with a constraint, then GCC 14 accepts the conversion: template concept FUN_constraint = requires(T &&t) { { std::type_identity_t{ std::forward(t) } }; }; template requires FUN_constraint void FUN(float); FUN( IC{} ); // OK https://gcc.godbolt.org/z/xP9z97v35 P2280 is necessary to make this work, because otherwise the usage of a reference in the requires-expression would make `t` again not usable in constant expressions. In conclusion, it seems that variant should indeed accept construction from IC. (I can't cross-check this report with other compilers as none of them implements P2280 yet.)
[Bug libstdc++/113060] std::variant converting constructor/assignment is non-conforming after P2280?
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113060 --- Comment #2 from Giuseppe D'Angelo --- (In reply to Jonathan Wakely from comment #1) > (In reply to Giuseppe D'Angelo from comment #0) > > GCC 14 implements P2280 (see #106650). > > N.B. if you say "Bug 106650" or "PR 106650" or "bug #106650" or pretty much > anything except just #106650 then bugzilla makes it a clickable link :) D'oh! > > it seems that variant should indeed accept construction from IC. > > I'm not convinced that this change to the semantics of std::variant was an > intended side effect of https://wg21.link/P2280 -- I think I'd prefer if the > committee confirmed it. Ok, I'll raise the question to LEWG. Or maybe EWG? > The standard doesn't say that it _should_ work in a constant expression, it > seems like you're assuming that because it's now possible to implement it so > that it works, that it's required to work. > > My reading of [variant.ctor] p14 is that "some invented variable x" is not a > constant expression, so using std::declval as a stand-in for "some invented > variable" is fine. But it does say how you get that x, you get it from the statement: Tj x[] = {std::forward(t)}; Nowhere in there's a call to declval. My reasoning is simply that if you spell FUN out for Ti = float, something like this (although the standard doesn't really specify the signature of FUN, which is not ideal): template auto FUN_float(T &&t) { float x[] = {std::forward(t)}; } then FUN_float(IC{}) is well-formed after P2280. Note that in general IC c; // not const!!! float f{c}; // OK is well-formed, and this is even before P2280. What seems to have changed with P2280 is that references do not disqualify expressions from being constant, and thus we can now detect this case a requires-expression that uses references. > If we made this change, then some cases that compile today would become > ill-formed, e.g. see PR 113007. Under your reading, conversion from the > constant 42 would be valid for both int64_t and double, and so the > initialization would be ill-formed. But it would be well-formed when using a > non-constant int equal to 42. Are you sure it would? FUN_double(42) should be still ill-formed (!), due to narrowing. My reasoning, in the context of P0870 (is_convertible_without_narrowing), is that int->double requires a lvalue-to-rvalue conversion, and then this kicks in https://eel.is/c++draft/expr.const#5.9 , disqualifying `t` from being treated as a constant expression. So then the list-initialization of `x` triggers narrowing. This is different from IC->double, where there's no lvalue-to-rvalue conversion (!), it's described here https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0870r5.html#ch5.9 Testcase: https://gcc.godbolt.org/z/rfvnfvYzs > Apart from the fact it would be a breaking change, the difference in > behaviour between runtime and compile time would be surprising. It would > also mean that std::is_constructible would be misleading: it would say you > can construct variant from 42, but when you try to do that it > would fail to compile. Sure, I'm really struggling at squaring the P2280 rules with detecting narrowing conversions, but I'm not sure if this would actually break. (And I'm not sure if something _else_ would break instead.)
[Bug libstdc++/112477] [13/14 Regression] Assignment of value-initialized iterators differs from value-initialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112477 --- Comment #7 from Giuseppe D'Angelo --- Hi, To be honest I didn't even notice it was a regression, but you're absolutely right, I can't reproduce my problem with GCC 12, only with GCC 13 (both in C++17 mode).
[Bug c++/116769] Instantiation of defaulted default constructor with non default constructible NDSMIs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116769 --- Comment #4 from Giuseppe D'Angelo --- Hi, thanks for investigating. That divergence is a bit worrying, I can't quite understand what's going on. Also, all compilers seem to accept this variation, which one would naively assume "equivalent" to the previous testcase: struct NDC { NDC(int); }; template struct Wrap { Wrap() : t() {} Wrap(const T &t) : t(t) {} T t; }; static_assert(std::is_default_constructible_v>);
[Bug c++/116769] New: Instantiation of defaulted default constructor with non default constructible NDSMIs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116769 Bug ID: 116769 Summary: Instantiation of defaulted default constructor with non default constructible NDSMIs Product: gcc Version: 14.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, Consider this testcase: #include struct NDC { NDC(int); }; template struct Wrap { Wrap() = default; Wrap(const T &t) : t(t) {} T t = T(); }; static_assert(!std::is_default_constructible_v>); GCC accepts this, while Clang / MSVC reject: https://gcc.godbolt.org/z/njh6Tvj19 Is this supposed to be ill-formed instead? Wrap's default constructor is going to be defined (and NOT deleted, https://eel.is/c++draft/class.default.ctor#2.5 should not apply here), and that should cause the =T() initialization for the member to fail to compile.
[Bug c++/116769] Instantiation of defaulted default constructor with non default constructible NDSMIs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116769 --- Comment #2 from Giuseppe D'Angelo --- > * rejects the code due to the default constructor being invalid. That would be Clang?