[gcc r14-10301] c++: lambda in pack expansion [PR115378]

2024-06-10 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:ff8105b4910f7dbee326cb36b01c16ac9bf10c4b

commit r14-10301-gff8105b4910f7dbee326cb36b01c16ac9bf10c4b
Author: Patrick Palka 
Date:   Fri Jun 7 12:12:30 2024 -0400

c++: lambda in pack expansion [PR115378]

Here find_parameter_packs_r is incorrectly treating the 'auto' return
type of a lambda as a parameter pack due to Concepts-TS specific logic
added in r6-4517, leading to confusion later when expanding the pattern.

Since we intend on removing Concepts TS support soon anyway, this patch
fixes this by restricting the problematic logic with flag_concepts_ts.
Doing so revealed that add_capture was relying on this logic to set
TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an pack expansion
init-capture, which we now need to do explicitly.

PR c++/115378

gcc/cp/ChangeLog:

* lambda.cc (lambda_capture_field_type): Set
TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture
pack expansion.
* pt.cc (find_parameter_packs_r) :
Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with
flag_concepts_ts.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic.
* g++.dg/template/pr95672.C: Likewise.
* g++.dg/cpp2a/lambda-targ5.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 5c761395402a730535983a5e49ef1775561ebc61)

Diff:
---
 gcc/cp/lambda.cc  |  3 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C |  2 +-
 gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++
 gcc/testsuite/g++.dg/template/pr95672.C   |  2 +-
 5 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 4b1f9391fee..5b5e31c141e 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
   outermost CV qualifiers of EXPR.  */
type = build_reference_type (type);
   if (uses_parameter_packs (expr))
-   /* Stick with 'auto' even if the type could be deduced.  */;
+   /* Stick with 'auto' even if the type could be deduced.  */
+   TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true;
   else
type = do_auto_deduction (type, expr, auto_node);
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d3f61e90422..c7aee66f068 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3942,7 +3942,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
 parameter pack (14.6.3), or the type-specifier-seq of a type-id that
 is a pack expansion, the invented template parameter is a template
 parameter pack.  */
-  if (ppd->type_pack_expansion_p && is_auto (t)
+  if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t)
  && TEMPLATE_TYPE_LEVEL (t) != 0)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
   if (TEMPLATE_TYPE_PARAMETER_PACK (t))
diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
index cedd661710c..4162361d14f 100644
--- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
+++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
@@ -1,7 +1,7 @@
 // PR c++/103497
 // { dg-do compile { target c++14 } }
 
-void foo(decltype(auto)... args);  // { dg-error "cannot declare a parameter 
with .decltype.auto.." }
+void foo(decltype(auto)... args);  // { dg-error "contains no parameter packs" 
}
 
 int main() {
   foo();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
new file mode 100644
index 000..efd4bb45d58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
@@ -0,0 +1,15 @@
+// PR c++/115378
+// { dg-do compile { target c++20 } }
+
+struct tt {};
+
+template
+constexpr auto __counter = 1;
+
+template 
+using _as_base = tt;
+
+template 
+struct env : _as_base>... {};
+
+env t;
diff --git a/gcc/testsuite/g++.dg/template/pr95672.C 
b/gcc/testsuite/g++.dg/template/pr95672.C
index c752b4a2c08..d97b8db2e97 100644
--- a/gcc/testsuite/g++.dg/template/pr95672.C
+++ b/gcc/testsuite/g++.dg/template/pr95672.C
@@ -1,3 +1,3 @@
 // PR c++/95672
 // { dg-do compile { target c++14 } }
-struct g_class : decltype  (auto) ... {  }; // { dg-error "invalid use of pack 
expansion" }
+struct g_class : decltype  (auto) ... {  }; // { dg-error "contains no 
parameter packs" }


[gcc r15-1103] c++: lambda in pack expansion [PR115378]

2024-06-07 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:5c761395402a730535983a5e49ef1775561ebc61

commit r15-1103-g5c761395402a730535983a5e49ef1775561ebc61
Author: Patrick Palka 
Date:   Fri Jun 7 12:12:30 2024 -0400

c++: lambda in pack expansion [PR115378]

Here find_parameter_packs_r is incorrectly treating the 'auto' return
type of a lambda as a parameter pack due to Concepts-TS specific logic
added in r6-4517, leading to confusion later when expanding the pattern.

Since we intend on removing Concepts TS support soon anyway, this patch
fixes this by restricting the problematic logic with flag_concepts_ts.
Doing so revealed that add_capture was relying on this logic to set
TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an pack expansion
init-capture, which we now need to do explicitly.

PR c++/115378

gcc/cp/ChangeLog:

* lambda.cc (lambda_capture_field_type): Set
TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture
pack expansion.
* pt.cc (find_parameter_packs_r) :
Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with
flag_concepts_ts.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic.
* g++.dg/template/pr95672.C: Likewise.
* g++.dg/cpp2a/lambda-targ5.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/lambda.cc  |  3 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C |  2 +-
 gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++
 gcc/testsuite/g++.dg/template/pr95672.C   |  2 +-
 5 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 630cc4eade1..0770417810e 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
   outermost CV qualifiers of EXPR.  */
type = build_reference_type (type);
   if (uses_parameter_packs (expr))
-   /* Stick with 'auto' even if the type could be deduced.  */;
+   /* Stick with 'auto' even if the type could be deduced.  */
+   TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true;
   else
type = do_auto_deduction (type, expr, auto_node);
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index abbba7c6746..607753ae6b7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3940,7 +3940,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
 parameter pack (14.6.3), or the type-specifier-seq of a type-id that
 is a pack expansion, the invented template parameter is a template
 parameter pack.  */
-  if (ppd->type_pack_expansion_p && is_auto (t)
+  if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t)
  && TEMPLATE_TYPE_LEVEL (t) != 0)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
   if (TEMPLATE_TYPE_PARAMETER_PACK (t))
diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
index cedd661710c..4162361d14f 100644
--- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
+++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
@@ -1,7 +1,7 @@
 // PR c++/103497
 // { dg-do compile { target c++14 } }
 
-void foo(decltype(auto)... args);  // { dg-error "cannot declare a parameter 
with .decltype.auto.." }
+void foo(decltype(auto)... args);  // { dg-error "contains no parameter packs" 
}
 
 int main() {
   foo();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
new file mode 100644
index 000..efd4bb45d58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
@@ -0,0 +1,15 @@
+// PR c++/115378
+// { dg-do compile { target c++20 } }
+
+struct tt {};
+
+template
+constexpr auto __counter = 1;
+
+template 
+using _as_base = tt;
+
+template 
+struct env : _as_base>... {};
+
+env t;
diff --git a/gcc/testsuite/g++.dg/template/pr95672.C 
b/gcc/testsuite/g++.dg/template/pr95672.C
index c752b4a2c08..d97b8db2e97 100644
--- a/gcc/testsuite/g++.dg/template/pr95672.C
+++ b/gcc/testsuite/g++.dg/template/pr95672.C
@@ -1,3 +1,3 @@
 // PR c++/95672
 // { dg-do compile { target c++14 } }
-struct g_class : decltype  (auto) ... {  }; // { dg-error "invalid use of pack 
expansion" }
+struct g_class : decltype  (auto) ... {  }; // { dg-error "contains no 
parameter packs" }


[PATCH] c++: lambda in pack expansion [PR115378]

2024-06-07 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/14?

-- >8 --

Here find_parameter_packs_r is incorrectly treating the 'auto' return
type of a lambda as a parameter pack due to Concepts-TS specific logic
added in r6-4517, leading to confusion later when expanding the pattern.

Since we intend on removing Concepts TS support soon anyway, this patch
fixes this by restricting the problematic logic with flag_concepts_ts.
Doing so revealed that add_capture was relying on this logic to set
TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an init-capture pack
expansion, which we now need to do explicitly.

PR c++/115378

gcc/cp/ChangeLog:

* lambda.cc (lambda_capture_field_type): Set
TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture
pack expansion.
* pt.cc (find_parameter_packs_r) :
Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with
flag_concepts_ts.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic.
* g++.dg/template/pr95672.C: Likewise.
* g++.dg/cpp2a/lambda-targ5.C: New test.
---
 gcc/cp/lambda.cc  |  3 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C |  2 +-
 gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++
 gcc/testsuite/g++.dg/template/pr95672.C   |  2 +-
 5 files changed, 20 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 630cc4eade1..0770417810e 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
   outermost CV qualifiers of EXPR.  */
type = build_reference_type (type);
   if (uses_parameter_packs (expr))
-   /* Stick with 'auto' even if the type could be deduced.  */;
+   /* Stick with 'auto' even if the type could be deduced.  */
+   TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true;
   else
type = do_auto_deduction (type, expr, auto_node);
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dfce1b3c359..6ee27d6fa16 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3940,7 +3940,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
 parameter pack (14.6.3), or the type-specifier-seq of a type-id that
 is a pack expansion, the invented template parameter is a template
 parameter pack.  */
-  if (ppd->type_pack_expansion_p && is_auto (t)
+  if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t)
  && TEMPLATE_TYPE_LEVEL (t) != 0)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
   if (TEMPLATE_TYPE_PARAMETER_PACK (t))
diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
index cedd661710c..4162361d14f 100644
--- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
+++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
@@ -1,7 +1,7 @@
 // PR c++/103497
 // { dg-do compile { target c++14 } }
 
-void foo(decltype(auto)... args);  // { dg-error "cannot declare a parameter 
with .decltype.auto.." }
+void foo(decltype(auto)... args);  // { dg-error "contains no parameter packs" 
}
 
 int main() {
   foo();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
new file mode 100644
index 000..efd4bb45d58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
@@ -0,0 +1,15 @@
+// PR c++/115378
+// { dg-do compile { target c++20 } }
+
+struct tt {};
+
+template
+constexpr auto __counter = 1;
+
+template 
+using _as_base = tt;
+
+template 
+struct env : _as_base>... {};
+
+env t;
diff --git a/gcc/testsuite/g++.dg/template/pr95672.C 
b/gcc/testsuite/g++.dg/template/pr95672.C
index c752b4a2c08..d97b8db2e97 100644
--- a/gcc/testsuite/g++.dg/template/pr95672.C
+++ b/gcc/testsuite/g++.dg/template/pr95672.C
@@ -1,3 +1,3 @@
 // PR c++/95672
 // { dg-do compile { target c++14 } }
-struct g_class : decltype  (auto) ... {  }; // { dg-error "invalid use of pack 
expansion" }
+struct g_class : decltype  (auto) ... {  }; // { dg-error "contains no 
parameter packs" }
-- 
2.45.2.409.g7b0defb391



[gcc r15-892] c++: canonicity of fn types w/ instantiated eh specs [PR115223]

2024-05-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:58b8c87b7fb281e35a6817cc91a292096fdc02dc

commit r15-892-g58b8c87b7fb281e35a6817cc91a292096fdc02dc
Author: Patrick Palka 
Date:   Wed May 29 04:49:37 2024 -0400

c++: canonicity of fn types w/ instantiated eh specs [PR115223]

When propagating structural equality in build_cp_fntype_variant, we
should consider structural equality of the exception-less variant, not
of the given type which might use structural equality only because it
has a (complex) noexcept-spec that we're intending to replace, as in
maybe_instantiate_noexcept which calls build_exception_variant using
the deferred-noexcept function type.  Otherwise we might pessimistically
use structural equality for a function type with a simple instantiated
noexcept-spec, leading to a LTO-triggered type verification failure if we
later use that (structural-equality) type as the canonical version of
some other variant.

PR c++/115223

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Propagate structural
equality of the exception-less variant.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept87.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc  |  4 
 gcc/testsuite/g++.dg/cpp0x/noexcept87.C | 11 +++
 2 files changed, 15 insertions(+)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index fe3f034d000..72dd46e1bd1 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2796,6 +2796,10 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
   bool complex_eh_spec_p = (cr && cr != noexcept_true_spec
&& !UNPARSED_NOEXCEPT_SPEC_P (cr));
 
+  if (!complex_eh_spec_p && TYPE_RAISES_EXCEPTIONS (type))
+/* We want to consider structural equality of the exception-less
+   variant since we'll be replacing the exception specification.  */
+type = build_cp_fntype_variant (type, rqual, /*raises=*/NULL_TREE, late);
   if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p)
 /* Propagate structural equality.  And always use structural equality
for function types with a complex noexcept-spec since their identity
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept87.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C
new file mode 100644
index 000..339569d15ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C
@@ -0,0 +1,11 @@
+// PR c++/115223
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -flto }
+
+template
+void f() noexcept(bool(T() || true));
+
+void g() { f(); }
+
+using type = void;
+type callDestructorIfNecessary() noexcept {}


[PATCH] c++: canonicity of fn types w/ instantiated eh specs [PR115223]

2024-05-25 Thread Patrick Palka
Bootstrap and regtest on x86_64-pc-linux-gnu in progress,
does this look OK for trunk if successful?

-- >8 --

When propagating structural equality in build_cp_fntype_variant, we
should consider structural equality of the exception-less variant, not
of the given type which might use structural equality only because of
the (complex) noexcept-spec we're intending to replace, as in
maybe_instantiate_noexcept which calls build_exception_variant using
the function type with a deferred noexcept-spec.  Otherwise we might
pessimisticly use structural equality for a function type with a simple
instantiated noexcept-spec, leading to a failed LTO-specific sanity
check if we later use that (structural-equality) type as the canonical
version of some other variant.

PR c++/115223

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Propagate structural
equality of the exception-less variant.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept87.C: New test.
---
 gcc/cp/tree.cc  |  4 
 gcc/testsuite/g++.dg/cpp0x/noexcept87.C | 11 +++
 2 files changed, 15 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept87.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 4d87661b4ad..f810b8cd777 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2796,6 +2796,10 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
   bool complex_eh_spec_p = (cr && cr != noexcept_true_spec
&& !UNPARSED_NOEXCEPT_SPEC_P (cr));
 
+  if (!complex_eh_spec_p && TYPE_RAISES_EXCEPTIONS (type))
+/* We want to consider structural equality of the exception-less
+   variant since we'll be replacing the exception specification.  */
+type = build_cp_fntype_variant (type, rqual, /*raises=*/NULL_TREE, late);
   if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p)
 /* Propagate structural equality.  And always use structural equality
for function types with a complex noexcept-spec since their identity
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept87.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C
new file mode 100644
index 000..60b1497472b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C
@@ -0,0 +1,11 @@
+// PR c++/115223
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -flto }
+
+template
+void f() noexcept(bool(T() || true));
+
+void g(int n) { f(); }
+
+using type = void;
+type callDestructorIfNecessary() noexcept {}
-- 
2.45.1.246.gb9cfe4845c



Re: [PATCH v2] libstdc++: Fix std::ranges::iota not included in numeric [PR108760]

2024-05-23 Thread Patrick Palka
On Fri, 17 May 2024, Michael Levine (BLOOMBERG/ 731 LEX) wrote:

> This is the revised version of my patch incorporating the provided feedback 
> from Patrick Palka and Jonathan Wakely.
> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> I moved out_value_result to , moved std::ranges:iota 
> into , removed my new test, and moved and renamed the existing test.

Nice, thanks!  The incremental changes seem good, but could you send a
single squashed patch containing all the changes?  That's what we'll end
up pushing after all.

> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> I then ran $ make -jN
> and $ make -jN install
> 
> Using the locally installed version, the following code compiled: 
> https://godbolt.org/z/33EPeqd1b
> 
> I tested my changes by running: $ make check-c++ -jN -k
> I personally found it difficult to understand the results of running the 
> tests.
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> From: Michael Levine (BLOOMBERG/ 731 LEX) At: 04/17/24 14:24:24 UTC-4:00
> To: libstd...@gcc.gnu.org, gcc-patches@gcc.gnu.org
> Subject: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric 
> [PR108760]
> 
> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including  
> when it should have been sufficient to only include .
> 
> When the patch is applied, the following code will compile: 
> https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> 
> 



Re: [PATCH v2] libstdc++: Fix std::ranges::iota not included in numeric [PR108760]

2024-05-23 Thread Patrick Palka
On Fri, 17 May 2024, Michael Levine (BLOOMBERG/ 731 LEX) wrote:

> This is the revised version of my patch incorporating the provided feedback 
> from Patrick Palka and Jonathan Wakely.
> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> I moved out_value_result to , moved std::ranges:iota 
> into , removed my new test, and moved and renamed the existing test.

Nice, thanks!  The incremental changes seem good, but could you send a
single squashed patch containing all the changes?  That's what we'll end
up pushing after all.

> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> I then ran $ make -jN
> and $ make -jN install
> 
> Using the locally installed version, the following code compiled: 
> https://godbolt.org/z/33EPeqd1b
> 
> I tested my changes by running: $ make check-c++ -jN -k
> I personally found it difficult to understand the results of running the 
> tests.
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> From: Michael Levine (BLOOMBERG/ 731 LEX) At: 04/17/24 14:24:24 UTC-4:00
> To: libstdc++@gcc.gnu.org, gcc-patc...@gcc.gnu.org
> Subject: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric 
> [PR108760]
> 
> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including  
> when it should have been sufficient to only include .
> 
> When the patch is applied, the following code will compile: 
> https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> 
> 



Re: [PATCH][14 backport] c++: Fix instantiation of imported temploid friends [PR114275]

2024-05-23 Thread Patrick Palka
 * g++.dg/modules/tpl-friend-12_f.C: New test.
>   * g++.dg/modules/tpl-friend-13_a.C: New test.
>   * g++.dg/modules/tpl-friend-13_b.C: New test.
>   * g++.dg/modules/tpl-friend-13_c.C: New test.
>   * g++.dg/modules/tpl-friend-13_d.C: New test.
>   * g++.dg/modules/tpl-friend-13_e.C: New test.
>   * g++.dg/modules/tpl-friend-13_f.C: New test.
>   * g++.dg/modules/tpl-friend-13_g.C: New test.
>   * g++.dg/modules/tpl-friend-14_a.C: New test.
>   * g++.dg/modules/tpl-friend-14_b.C: New test.
>   * g++.dg/modules/tpl-friend-14_c.C: New test.
>   * g++.dg/modules/tpl-friend-14_d.C: New test.
>   * g++.dg/modules/tpl-friend-9.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> Reviewed-by: Jason Merrill 
> Reviewed-by: Patrick Palka 
> ---
>  gcc/cp/cp-tree.h  |  3 +
>  gcc/cp/decl.cc| 41 ++
>  gcc/cp/module.cc  | 75 +++
>  gcc/cp/name-lookup.cc | 53 +
>  gcc/cp/pt.cc  | 32 +++-
>  .../g++.dg/modules/tpl-friend-10_a.C  | 15 
>  .../g++.dg/modules/tpl-friend-10_b.C  |  5 ++
>  .../g++.dg/modules/tpl-friend-10_c.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-10_d.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-11_a.C  | 14 
>  .../g++.dg/modules/tpl-friend-11_b.C  |  5 ++
>  .../g++.dg/modules/tpl-friend-12_a.C  | 10 +++
>  .../g++.dg/modules/tpl-friend-12_b.C  |  9 +++
>  .../g++.dg/modules/tpl-friend-12_c.C  | 10 +++
>  .../g++.dg/modules/tpl-friend-12_d.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-12_e.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-12_f.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-13_a.C  | 13 
>  .../g++.dg/modules/tpl-friend-13_b.C  | 11 +++
>  .../g++.dg/modules/tpl-friend-13_c.C  | 13 
>  .../g++.dg/modules/tpl-friend-13_d.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-13_e.C  | 18 +
>  .../g++.dg/modules/tpl-friend-13_f.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-13_g.C  | 11 +++
>  .../g++.dg/modules/tpl-friend-14_a.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-14_b.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-14_c.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-14_d.C  |  9 +++
>  gcc/testsuite/g++.dg/modules/tpl-friend-9.C   | 13 
>  29 files changed, 418 insertions(+), 17 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-11_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-11_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_e.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_f.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_f.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_g.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-9.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 9975dc78456..0c14241fce7 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7417,6 +7417,8 @@ extern unsigned get_importing_module (tree, bool = 
> false) ATTRIBUTE_PURE;
>  extern void set_instantiating_module (tree);
>  extern void set_defining_module (tree);
>  extern void maybe_key_decl (tree ctx, tree decl);
> +extern void propagate_defining_module (tree decl, tree orig);
> +extern void remove_defining_module (tree decl);
>  
>  extern void man

Re: [PATCH v26 01/13] libstdc++: Optimize std::is_const compilation performance

2024-05-23 Thread Patrick Palka
On Sat, 11 May 2024, Ken Matsui wrote:

> This patch optimizes the compilation performance of std::is_const
> by dispatching to the new __is_const built-in trait.

This patch series LGTM

> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_const): Use __is_const built-in
>   trait.
>   (is_const_v): Likewise.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 12 
>  1 file changed, 12 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index b441bf9908f..8df0cf3ac3b 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -835,6 +835,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Type properties.
>  
>/// is_const
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
> +  template
> +struct is_const
> +: public __bool_constant<__is_const(_Tp)>
> +{ };
> +#else
>template
>  struct is_const
>  : public false_type { };
> @@ -842,6 +848,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_const<_Tp const>
>  : public true_type { };
> +#endif
>  
>/// is_volatile
>template
> @@ -3331,10 +3338,15 @@ template 
>inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
>  #endif
>  
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
> +template 
> +  inline constexpr bool is_const_v = __is_const(_Tp);
> +#else
>  template 
>inline constexpr bool is_const_v = false;
>  template 
>inline constexpr bool is_const_v = true;
> +#endif
>  
>  #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
>  template 
> -- 
> 2.44.0
> 
> 



Re: [PATCH v26 01/13] libstdc++: Optimize std::is_const compilation performance

2024-05-23 Thread Patrick Palka
On Sat, 11 May 2024, Ken Matsui wrote:

> This patch optimizes the compilation performance of std::is_const
> by dispatching to the new __is_const built-in trait.

This patch series LGTM

> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_const): Use __is_const built-in
>   trait.
>   (is_const_v): Likewise.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 12 
>  1 file changed, 12 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index b441bf9908f..8df0cf3ac3b 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -835,6 +835,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Type properties.
>  
>/// is_const
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
> +  template
> +struct is_const
> +: public __bool_constant<__is_const(_Tp)>
> +{ };
> +#else
>template
>  struct is_const
>  : public false_type { };
> @@ -842,6 +848,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_const<_Tp const>
>  : public true_type { };
> +#endif
>  
>/// is_volatile
>template
> @@ -3331,10 +3338,15 @@ template 
>inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
>  #endif
>  
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
> +template 
> +  inline constexpr bool is_const_v = __is_const(_Tp);
> +#else
>  template 
>inline constexpr bool is_const_v = false;
>  template 
>inline constexpr bool is_const_v = true;
> +#endif
>  
>  #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
>  template 
> -- 
> 2.44.0
> 
> 



Re: [PATCH] libstdc++: Implement ranges::concat_view from P2542R7

2024-05-23 Thread Patrick Palka
On Mon, 29 Apr 2024, Jonathan Wakely wrote:

> On Mon, 22 Apr 2024 at 22:43, Patrick Palka wrote:
> >
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  More tests
> > are needed but I figured I'd submit this now for possible consideration into
> > GCC 14 since we're getting close to release..  All changes are confined to
> > C++26.
> 
> OK for trunk. Maybe we can backport it for 14.2 later, but not now.
> Sorry for the review being slow.

No worries, thanks a lot!  I pushed this now, though I realized I didn't
implement the latest/approved revision of the paper, R8 vs R7, which
notably changes the constraints on operator-(it, default_sentinel).
Since that seems to be the only significant change, I reckon I'll fix
that in a follow-up patch.

> 
> 
> >
> > -- >8 --
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/version.def (ranges_concat): Define.
> > * include/bits/version.h: Regenerate.
> > * include/std/ranges (__detail::__concat_reference_t): Define
> > for C++26.
> > (__detail::__concat_value_t): Likewise.
> > (__detail::__concat_rvalue_reference_t): Likewise.
> > (__detail::__concat_indirectly_readable_impl): Likewise.
> > (__detail::__concat_indirectly_readable): Likewise.
> > (__detail::__concatable): Likewise.
> > (__detail::__all_but_last_common): Likewise.
> > (__detail::__concat_is_random_access): Likewise.
> > (__detail::__concat_is_bidirectional): Likewise.
> > (__detail::__last_is_common): Likewise.
> > (concat_view): Likewise.
> > (__detail::__concat_view_iter_cat): Likewise.
> > (concat_view::iterator): Likewise.
> > (views::__detail::__can_concat_view): Likewise.
> > (views::_Concat, views::concat): Likewise.
> > * testsuite/std/ranges/concat/1.cc: New test.
> > ---
> >  libstdc++-v3/include/bits/version.def |   8 +
> >  libstdc++-v3/include/bits/version.h   |  10 +
> >  libstdc++-v3/include/std/ranges   | 584 ++
> >  libstdc++-v3/testsuite/std/ranges/concat/1.cc |  61 ++
> >  4 files changed, 663 insertions(+)
> >  create mode 100644 libstdc++-v3/testsuite/std/ranges/concat/1.cc
> >
> > diff --git a/libstdc++-v3/include/bits/version.def 
> > b/libstdc++-v3/include/bits/version.def
> > index 5c0477fb61e..af13090c094 100644
> > --- a/libstdc++-v3/include/bits/version.def
> > +++ b/libstdc++-v3/include/bits/version.def
> > @@ -1796,6 +1796,14 @@ ftms = {
> >};
> >  };
> >
> > +ftms = {
> > +  name = ranges_concat;
> > +  values = {
> > +v = 202403;
> > +cxxmin = 26;
> > +  };
> > +};
> > +
> >  // Standard test specifications.
> >  stds[97] = ">= 199711L";
> >  stds[03] = ">= 199711L";
> > diff --git a/libstdc++-v3/include/bits/version.h 
> > b/libstdc++-v3/include/bits/version.h
> > index 65e708c73fb..1f27bfe050d 100644
> > --- a/libstdc++-v3/include/bits/version.h
> > +++ b/libstdc++-v3/include/bits/version.h
> > @@ -2003,4 +2003,14 @@
> >  #endif /* !defined(__cpp_lib_to_string) && 
> > defined(__glibcxx_want_to_string) */
> >  #undef __glibcxx_want_to_string
> >
> > +#if !defined(__cpp_lib_ranges_concat)
> > +# if (__cplusplus >  202302L)
> > +#  define __glibcxx_ranges_concat 202403L
> > +#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
> > +#   define __cpp_lib_ranges_concat 202403L
> > +#  endif
> > +# endif
> > +#endif /* !defined(__cpp_lib_ranges_concat) && 
> > defined(__glibcxx_want_ranges_concat) */
> > +#undef __glibcxx_want_ranges_concat
> > +
> >  #undef __glibcxx_want_all
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index afce818376b..28a39bf6f34 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -55,6 +55,7 @@
> >  #define __glibcxx_want_ranges_as_const
> >  #define __glibcxx_want_ranges_as_rvalue
> >  #define __glibcxx_want_ranges_cartesian_product
> > +#define __glibcxx_want_ranges_concat
> >  #define __glibcxx_want_ranges_chunk
> >  #define __glibcxx_want_ranges_chunk_by
> >  #define __glibcxx_want_ranges_enumerate
> > @@ -9514,6 +9515,589 @@ namespace __detail
> >  } // namespace ranges
> >  #endif // __cpp_lib_ranges_to_container
> >
> > +#if __cpp_lib_ranges_concat // C++ >= C+

Re: [PATCH] libstdc++: Implement ranges::concat_view from P2542R7

2024-05-23 Thread Patrick Palka
On Mon, 29 Apr 2024, Jonathan Wakely wrote:

> On Mon, 22 Apr 2024 at 22:43, Patrick Palka wrote:
> >
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  More tests
> > are needed but I figured I'd submit this now for possible consideration into
> > GCC 14 since we're getting close to release..  All changes are confined to
> > C++26.
> 
> OK for trunk. Maybe we can backport it for 14.2 later, but not now.
> Sorry for the review being slow.

No worries, thanks a lot!  I pushed this now, though I realized I didn't
implement the latest/approved revision of the paper, R8 vs R7, which
notably changes the constraints on operator-(it, default_sentinel).
Since that seems to be the only significant change, I reckon I'll fix
that in a follow-up patch.

> 
> 
> >
> > -- >8 --
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/version.def (ranges_concat): Define.
> > * include/bits/version.h: Regenerate.
> > * include/std/ranges (__detail::__concat_reference_t): Define
> > for C++26.
> > (__detail::__concat_value_t): Likewise.
> > (__detail::__concat_rvalue_reference_t): Likewise.
> > (__detail::__concat_indirectly_readable_impl): Likewise.
> > (__detail::__concat_indirectly_readable): Likewise.
> > (__detail::__concatable): Likewise.
> > (__detail::__all_but_last_common): Likewise.
> > (__detail::__concat_is_random_access): Likewise.
> > (__detail::__concat_is_bidirectional): Likewise.
> > (__detail::__last_is_common): Likewise.
> > (concat_view): Likewise.
> > (__detail::__concat_view_iter_cat): Likewise.
> > (concat_view::iterator): Likewise.
> > (views::__detail::__can_concat_view): Likewise.
> > (views::_Concat, views::concat): Likewise.
> > * testsuite/std/ranges/concat/1.cc: New test.
> > ---
> >  libstdc++-v3/include/bits/version.def |   8 +
> >  libstdc++-v3/include/bits/version.h   |  10 +
> >  libstdc++-v3/include/std/ranges   | 584 ++
> >  libstdc++-v3/testsuite/std/ranges/concat/1.cc |  61 ++
> >  4 files changed, 663 insertions(+)
> >  create mode 100644 libstdc++-v3/testsuite/std/ranges/concat/1.cc
> >
> > diff --git a/libstdc++-v3/include/bits/version.def 
> > b/libstdc++-v3/include/bits/version.def
> > index 5c0477fb61e..af13090c094 100644
> > --- a/libstdc++-v3/include/bits/version.def
> > +++ b/libstdc++-v3/include/bits/version.def
> > @@ -1796,6 +1796,14 @@ ftms = {
> >};
> >  };
> >
> > +ftms = {
> > +  name = ranges_concat;
> > +  values = {
> > +v = 202403;
> > +cxxmin = 26;
> > +  };
> > +};
> > +
> >  // Standard test specifications.
> >  stds[97] = ">= 199711L";
> >  stds[03] = ">= 199711L";
> > diff --git a/libstdc++-v3/include/bits/version.h 
> > b/libstdc++-v3/include/bits/version.h
> > index 65e708c73fb..1f27bfe050d 100644
> > --- a/libstdc++-v3/include/bits/version.h
> > +++ b/libstdc++-v3/include/bits/version.h
> > @@ -2003,4 +2003,14 @@
> >  #endif /* !defined(__cpp_lib_to_string) && 
> > defined(__glibcxx_want_to_string) */
> >  #undef __glibcxx_want_to_string
> >
> > +#if !defined(__cpp_lib_ranges_concat)
> > +# if (__cplusplus >  202302L)
> > +#  define __glibcxx_ranges_concat 202403L
> > +#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
> > +#   define __cpp_lib_ranges_concat 202403L
> > +#  endif
> > +# endif
> > +#endif /* !defined(__cpp_lib_ranges_concat) && 
> > defined(__glibcxx_want_ranges_concat) */
> > +#undef __glibcxx_want_ranges_concat
> > +
> >  #undef __glibcxx_want_all
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index afce818376b..28a39bf6f34 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -55,6 +55,7 @@
> >  #define __glibcxx_want_ranges_as_const
> >  #define __glibcxx_want_ranges_as_rvalue
> >  #define __glibcxx_want_ranges_cartesian_product
> > +#define __glibcxx_want_ranges_concat
> >  #define __glibcxx_want_ranges_chunk
> >  #define __glibcxx_want_ranges_chunk_by
> >  #define __glibcxx_want_ranges_enumerate
> > @@ -9514,6 +9515,589 @@ namespace __detail
> >  } // namespace ranges
> >  #endif // __cpp_lib_ranges_to_container
> >
> > +#if __cpp_lib_ranges_concat // C++ >= C+

[gcc r15-809] libstdc++: Implement ranges::concat_view from P2542R7

2024-05-23 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:66d2a76dcf625f8dbe43d3c512e9c43f588fdc25

commit r15-809-g66d2a76dcf625f8dbe43d3c512e9c43f588fdc25
Author: Patrick Palka 
Date:   Thu May 23 18:03:56 2024 -0400

libstdc++: Implement ranges::concat_view from P2542R7

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_concat): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__concat_reference_t): Define
for C++26.
(__detail::__concat_value_t): Likewise.
(__detail::__concat_rvalue_reference_t): Likewise.
(__detail::__concat_indirectly_readable_impl): Likewise.
(__detail::__concat_indirectly_readable): Likewise.
(__detail::__concatable): Likewise.
(__detail::__all_but_last_common): Likewise.
(__detail::__concat_is_random_access): Likewise.
(__detail::__concat_is_bidirectional): Likewise.
(__detail::__last_is_common): Likewise.
(concat_view): Likewise.
(__detail::__concat_view_iter_cat): Likewise.
(concat_view::iterator): Likewise.
(views::__detail::__can_concat_view): Likewise.
(views::_Concat, views::concat): Likewise.
* testsuite/std/ranges/concat/1.cc: New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/version.def |   8 +
 libstdc++-v3/include/bits/version.h   |  10 +
 libstdc++-v3/include/std/ranges   | 580 ++
 libstdc++-v3/testsuite/std/ranges/concat/1.cc |  74 
 4 files changed, 672 insertions(+)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 5cbc9d1a8d8..683b967d54b 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1805,6 +1805,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_concat;
+  values = {
+v = 202403;
+cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 164ebed4983..4850041c0a3 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2013,4 +2013,14 @@
 #endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
 #undef __glibcxx_want_to_string
 
+#if !defined(__cpp_lib_ranges_concat)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_concat 202403L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
+#   define __cpp_lib_ranges_concat 202403L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_concat) && 
defined(__glibcxx_want_ranges_concat) */
+#undef __glibcxx_want_ranges_concat
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index afce818376b..b1e827c9a72 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -55,6 +55,7 @@
 #define __glibcxx_want_ranges_as_const
 #define __glibcxx_want_ranges_as_rvalue
 #define __glibcxx_want_ranges_cartesian_product
+#define __glibcxx_want_ranges_concat
 #define __glibcxx_want_ranges_chunk
 #define __glibcxx_want_ranges_chunk_by
 #define __glibcxx_want_ranges_enumerate
@@ -9514,6 +9515,585 @@ namespace __detail
 } // namespace ranges
 #endif // __cpp_lib_ranges_to_container
 
+#if __cpp_lib_ranges_concat // C++ >= C++26
+namespace ranges
+{
+  namespace __detail
+  {
+template
+  using __concat_reference_t = 
common_reference_t...>;
+
+template
+  using __concat_value_t = common_type_t...>;
+
+template
+  using __concat_rvalue_reference_t
+   = common_reference_t...>;
+
+template
+  concept __concat_indirectly_readable_impl = requires(const _It __it) {
+   { *__it } -> convertible_to<_Ref>;
+   { ranges::iter_move(__it) } -> convertible_to<_RRef>;
+  };
+
+template
+  concept __concat_indirectly_readable
+   = common_reference_with<__concat_reference_t<_Rs...>&&, 
__concat_value_t<_Rs...>&>
+ && common_reference_with<__concat_reference_t<_Rs...>&&,
+  __concat_rvalue_reference_t<_Rs...>&&>
+ && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
+  __concat_value_t<_Rs...> const&>
+ && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
+   
__concat_rvalue_reference_t<_Rs...>,
+   iterator_t<_Rs>>
+ && ...);
+
+template
+  concept __concatable = requires 

Re: [PATCH] c++: alias CTAD and copy deduction guide [PR115198]

2024-05-23 Thread Patrick Palka
On Thu, 23 May 2024, Jason Merrill wrote:

> On 5/23/24 14:06, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/14?
> > 
> > -- >8 --
> > 
> > Here we're neglecting to update DECL_NAME during the alias CTAD guide
> > transformation, which causes copy_guide_p to return false for the
> > transformed copy deduction guide since DECL_NAME is still __dguide_C
> > with TREE_TYPE C but it should be __dguide_A with TREE_TYPE A
> > (equivalently C).  This ultimately results in ambiguity during
> > overload resolution between the copy deduction guide vs copy ctor guide.
> > 
> > This patch makes us update DECL_NAME of a transformed guide accordingly
> > during alias CTAD.  This eventually needs to be done for inherited CTAD
> > too, but it's not clear what identifier to use there since it has to be
> > unique for each derived/base pair.  For
> > 
> >template struct A { ... };
> >template struct B : A { using A::A; }
> > 
> > at first glance it'd be reasonable to give inherited guides a name of
> > __dguide_B with TREE_TYPE A, but since that name is already
> > used B's own guides its TREE_TYPE is already B.
> 
> Why can't it be the same __dguide_B with TREE_TYPE B?

Ah because copy_guide_p relies on TREE_TYPE in order to recognize a copy
deduction guide, and with that TREE_TYPE it would still incorrectly
return false for an inherited copy deduction guide, e.g.

  A(A) -> A

gets transformed into

  B(A) -> B

and A != B so copy_guide_p returns false.

But it just occurred to me that this TREE_TYPE clobbering of the
__dguide_foo identifier already happens if we have two class templates
with the same name in different namespaces, since the identifier
contains only the terminal name.  Maybe this suggests that we should
use a tree flag to track whether a guide is the copy deduction guide
instead of setting TREE_TYPE of DECL_NAME?

> 
> > PR c++/115198
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (alias_ctad_tweaks): Update DECL_NAME of a transformed
> > guide during alias CTAD.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/class-deduction-alias22.C: New test.
> > ---
> >   gcc/cp/pt.cc   |  9 -
> >   .../g++.dg/cpp2a/class-deduction-alias22.C | 14 ++
> >   2 files changed, 22 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 0c4d96cf768..58873057abc 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -30304,13 +30304,14 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> >any).  */
> >   enum { alias, inherited } ctad_kind;
> > -  tree atype, fullatparms, utype;
> > +  tree atype, fullatparms, utype, name;
> > if (TREE_CODE (tmpl) == TEMPLATE_DECL)
> >   {
> > ctad_kind = alias;
> > atype = TREE_TYPE (tmpl);
> > fullatparms = DECL_TEMPLATE_PARMS (tmpl);
> > utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
> > +  name = dguide_name (tmpl);
> >   }
> > else
> >   {
> > @@ -30318,6 +30319,10 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> > atype = NULL_TREE;
> > fullatparms = TREE_PURPOSE (tmpl);
> > utype = TREE_VALUE (tmpl);
> > +  /* FIXME: What name should we give inherited guides?  It needs to be
> > +unique to the derived/base pair so that we don't clobber an earlier
> > +setting of TREE_TYPE.  */
> > +  name = NULL_TREE;
> >   }
> >   tsubst_flags_t complain = tf_warning_or_error;
> > @@ -30413,6 +30418,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> > }
> >   if (g == error_mark_node)
> > continue;
> > + if (name)
> > +   DECL_NAME (g) = name;
> >   if (nfparms == 0)
> > {
> >   /* The targs are all non-dependent, so g isn't a template.  */
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > new file mode 100644
> > index 000..9c6c841166a
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/115198
> > +// { dg-do compile { target c++20 } }
> > +
> > +template
> > +struct C {
> > +  C() = default;
> > +  C(const C&) = default;
> > +};
> > +
> > +template
> > +using A = C;
> > +
> > +C c;
> > +A a = c; // { dg-bogus "ambiguous" }
> 
> 



[PATCH] c++: alias CTAD and copy deduction guide [PR115198]

2024-05-23 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/14?

-- >8 --

Here we're neglecting to update DECL_NAME during the alias CTAD guide
transformation, which causes copy_guide_p to return false for the
transformed copy deduction guide since DECL_NAME is still __dguide_C
with TREE_TYPE C but it should be __dguide_A with TREE_TYPE A
(equivalently C).  This ultimately results in ambiguity during
overload resolution between the copy deduction guide vs copy ctor guide.

This patch makes us update DECL_NAME of a transformed guide accordingly
during alias CTAD.  This eventually needs to be done for inherited CTAD
too, but it's not clear what identifier to use there since it has to be
unique for each derived/base pair.  For

  template struct A { ... };
  template struct B : A { using A::A; }

at first glance it'd be reasonable to give inherited guides a name of
__dguide_B with TREE_TYPE A, but since that name is already
used B's own guides its TREE_TYPE is already B.

PR c++/115198

gcc/cp/ChangeLog:

* pt.cc (alias_ctad_tweaks): Update DECL_NAME of a transformed
guide during alias CTAD.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-alias22.C: New test.
---
 gcc/cp/pt.cc   |  9 -
 .../g++.dg/cpp2a/class-deduction-alias22.C | 14 ++
 2 files changed, 22 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 0c4d96cf768..58873057abc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30304,13 +30304,14 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  any).  */
 
   enum { alias, inherited } ctad_kind;
-  tree atype, fullatparms, utype;
+  tree atype, fullatparms, utype, name;
   if (TREE_CODE (tmpl) == TEMPLATE_DECL)
 {
   ctad_kind = alias;
   atype = TREE_TYPE (tmpl);
   fullatparms = DECL_TEMPLATE_PARMS (tmpl);
   utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+  name = dguide_name (tmpl);
 }
   else
 {
@@ -30318,6 +30319,10 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
   atype = NULL_TREE;
   fullatparms = TREE_PURPOSE (tmpl);
   utype = TREE_VALUE (tmpl);
+  /* FIXME: What name should we give inherited guides?  It needs to be
+unique to the derived/base pair so that we don't clobber an earlier
+setting of TREE_TYPE.  */
+  name = NULL_TREE;
 }
 
   tsubst_flags_t complain = tf_warning_or_error;
@@ -30413,6 +30418,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
}
  if (g == error_mark_node)
continue;
+ if (name)
+   DECL_NAME (g) = name;
  if (nfparms == 0)
{
  /* The targs are all non-dependent, so g isn't a template.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
new file mode 100644
index 000..9c6c841166a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
@@ -0,0 +1,14 @@
+// PR c++/115198
+// { dg-do compile { target c++20 } }
+
+template
+struct C {
+  C() = default;
+  C(const C&) = default;
+};
+
+template
+using A = C;
+
+C c;
+A a = c; // { dg-bogus "ambiguous" }
-- 
2.45.1.216.g4365c6fcf9



[gcc r15-779] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-22 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:3c98d06a9016a0fa3a806879bd168f13b8a606f8

commit r15-779-g3c98d06a9016a0fa3a806879bd168f13b8a606f8
Author: Patrick Palka 
Date:   Wed May 22 17:45:04 2024 -0400

c++: canonicity of fn types w/ complex eh specs [PR115159]

Here the member functions QList::g and QList::h are given the same
function type by build_cp_fntype_variant since their noexcept-specs are
equivalent according to cp_tree_equal.  In doing so however this means
that the function type of QList::h refers to a function parameter from
QList::g, which ends up confusing modules streaming.

I'm not sure if modules can be fixed to handle this situation, but
regardless it seems weird in principle that a function parameter can
escape in such a way.  The analogous situation with a trailing return
type and decltype

  auto g(QList ) -> decltype(f(other));
  auto h(QList ) -> decltype(f(other));

behaves better because we don't canonicalize decltype, and so the
function types of g and h are non-canonical and therefore not shared.

In light of this, it seems natural to treat function types with complex
noexcept-specs as non-canonical as well so that each such function
declaration is given a unique function type node.  (The main benefit of
type canonicalization is to speed up repeated type comparisons, but it
should be rare to repeatedly compare two otherwise compatible function
types with complex noexcept-specs.)

To that end, this patch strengthens the ce_exact case of comp_except_specs
to require identity instead of equivalence of the noexcept-spec so that
build_cp_fntype_variant doesn't reuse a variant when it shouldn't.  In
turn we need to use structural equality for types with a complex eh spec.
This lets us get rid of the tricky handling of canonical types when updating
unparsed noexcept-spec variants.

PR c++/115159

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Always use structural
equality for types with a complex exception specification.
(fixup_deferred_exception_variants): Use structural equality
for adjusted variants.
* typeck.cc (comp_except_specs): Require == instead of
cp_tree_equal for ce_exact noexcept-spec comparison.

gcc/testsuite/ChangeLog:

* g++.dg/modules/noexcept-2_a.H: New test.
* g++.dg/modules/noexcept-2_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc  | 48 ++---
 gcc/cp/typeck.cc|  4 ++-
 gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++
 gcc/testsuite/g++.dg/modules/noexcept-2_b.C |  4 +++
 4 files changed, 41 insertions(+), 39 deletions(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 9d37d255d8d..4d87661b4ad 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2793,9 +2793,13 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 
   /* Canonicalize the exception specification.  */
   tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
+  bool complex_eh_spec_p = (cr && cr != noexcept_true_spec
+   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
 
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
-/* Propagate structural equality. */
+  if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p)
+/* Propagate structural equality.  And always use structural equality
+   for function types with a complex noexcept-spec since their identity
+   may depend on e.g. whether comparing_specializations is set.  */
 SET_TYPE_STRUCTURAL_EQUALITY (v);
   else if (TYPE_CANONICAL (type) != type || cr != raises || late)
 /* Build the underlying canonical type, since it is different
@@ -2812,55 +2816,23 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 /* TYPE is a function or method type with a deferred exception
specification that has been parsed to RAISES.  Fixup all the type
variants that are affected in place.  Via decltype &| noexcept
-   tricks, the unparsed spec could have escaped into the type system.
-   The general case is hard to fixup canonical types for.  */
+   tricks, the unparsed spec could have escaped into the type system.  */
 
 void
 fixup_deferred_exception_variants (tree type, tree raises)
 {
   tree original = TYPE_RAISES_EXCEPTIONS (type);
-  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
 
   gcc_checking_assert (UNPARSED_NOEXCEPT_SPEC_P (original));
 
-  /* Though sucky, this walk will process the canonical variants
- first.  */
-  tree prev = NULL_TREE;
   for (tree variant = TYPE_MAIN_VARIANT (type);
-   variant; prev = variant, variant = TYPE_NEXT_VARIANT (variant))
+   variant; variant = TYPE_NEXT_VARIANT (variant))
 if (TYPE_RAISES_EXCEPT

Re: [PATCH] Fix auto deduction for template specialization scopes [114915].

2024-05-22 Thread Patrick Palka
On Wed, 22 May 2024, Jason Merrill wrote:

> Thanks for the patch!
> 
> Please review https://gcc.gnu.org/contribute.html for more details of the
> format patches should have.  In particular, you don't seem to have a copyright
> assignment on file with the FSF, so you'll need to either do that or certify
> that the contribution is under the DCO.
> 
> Also, you need a component tag (c++:) in the subject line, and ChangeLog
> entries in the commit message.  Note what contribute.html says about git
> gcc-commit-mklog, which makes that a lot simpler.
> 
> On 5/1/24 18:52, Seyed Sajad Kahani wrote:
> > When deducing auto for `adc_return_type`, `adc_variable_type`, and
> > `adc_decomp_type` contexts (at the usage time), we try to resolve the
> > outermost template arguments to be used for satisfaction. This is done by
> > one of the following, depending on the scope:
> > 
> > 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
> > extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> > 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with
> > other conditions) for non-function scope variable declaration deductions
> > (decl.cc:8527).
> > 
> > Then, we do not retrieve the deeper layers of the template arguments;
> > instead, we fill the missing levels with dummy levels (pt.cc:31260).
> > 
> > The problem (that is shown in PR114915) is that we do not consider the case
> > where the deduction happens in a template specialization scope. In this
> > case, the type is not dependent on the outermost template arguments (which
> > are the specialization arguments). Yet, we still resolve the outermost
> > template arguments, and then the number of layers in the template arguments
> > exceeds the number of levels in the type. This causes the missing levels to
> > be negative. This leads to the rejection of valid code and ICEs (like
> > segfault) in the release mode. In the debug mode, it is possible to show as
> > an assertion failure (when creating a tree_vec with a negative size).
> > The code that generates the issue is added to the test suite as
> > `g++.dg/cpp2a/concepts-placeholder14.C`.
> 
> This testcase could use more cases, like variable template specialization
> (both full and partial) and member functions where not all enclosing classes
> are fully specialized.

Note I think the latest version of the patch is
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651805.html
which has more test coverage and takes a more context oblivious approach
that keeps the innermost arguments if there's an excess, based on some
earlier discussion e.g.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650834.html
This should do the right thing at least until we implement explicit
specializations in template scope (CWG 727)

> 
> > This patch fixes the issue by checking that the template usage, whose
> > arguments are going to be used for satisfaction, is not a partial or
> > explicit specialization (and therefore it is an implicit or explicit
> > instantiation). This check is done in the two only places that affect the
> > `outer_targs` for the mentioned contexts.
> 
> It seems like we want a function to use instead of DECL_TI_ARGS to get the
> args for parameters that are actually in scope in the definition that we're
> substituting into.  In the case of a full specialization, that would be
> NULL_TREE, but it's more complicated for partial specializations.
> 
> This function should probably go after outer_template_args in pt.cc.
> 
> > One might ask why this is not implemented as a simple `missing_level > 0`
> > check. The reason is that the recovery from the negative `missing_levels`
> > will not be easy, and it is not clear how to recover from it. Therefore, it
> > is better to prevent it from happening.
> 
> But you still have that check in the patch.  Would it be better as an assert?
> 
> Thanks,
> Jason
> 
> 



Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-22 Thread Patrick Palka
On Tue, 21 May 2024, Jason Merrill wrote:

> On 5/21/24 21:55, Patrick Palka wrote:
> > On Tue, 21 May 2024, Jason Merrill wrote:
> > 
> > > On 5/21/24 17:27, Patrick Palka wrote:
> > > > On Tue, 21 May 2024, Jason Merrill wrote:
> > > > 
> > > > > On 5/21/24 15:36, Patrick Palka wrote:
> > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > > > OK for trunk?
> > > > > > 
> > > > > > Alternatively, I considered fixing this by incrementing
> > > > > > comparing_specializations around the call to comp_except_specs in
> > > > > > cp_check_qualified_type, but generally for types whose identity
> > > > > > depends on whether comparing_specializations is set we need to
> > > > > > use structural equality anyway IIUC.
> > > > > 
> > > > > Why not both?
> > > > 
> > > > I figured the latter change isn't necessary/observable since
> > > > comparing_specializations would only make a difference for complex
> > > > exception specifications, and with this patch we won't even call
> > > > cp_check_qualified_type on a complex eh spec.
> > > 
> > > My concern is that if we're building a function type multiple times with
> > > the
> > > same noexcept-spec, this patch would mean creating multiple equivalent
> > > function types instead of reusing one already created for the same
> > > function.
> > > 
> > > > > > +  bool complex_p = (cr && cr != noexcept_true_spec
> > > > > > +   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> > > > > 
> > > > > Why treat unparsed specs differently from parsed ones?
> > > > 
> > > > Unparsed specs are unique according to cp_tree_equal, so in turn
> > > > function types with unparsed specs are unique, so it should be safe to
> > > > treat such types as canonical.  I'm not sure if this optimization
> > > > matters though; I'm happy to remove this case.
> > > 
> > > The idea that this optimization could make a difference raised the concern
> > > above.
> > 
> > Aha, makes sense.  To that end it seems we could strengthen the ce_exact
> > in comp_except_specs to require == instead of cp_tree_equal equality
> > when comparing two noexcept-specs; the only ce_exact callers are
> > cp_check_qualified_type and cxx_type_hash_eq, which should be fine with
> > that strengthening.  This way, we at least do try to reuse a variant if
> > the (complex or unparsed) noexcept-spec is exactly the same.
> 
> Sounds good.
> 
> Given that, we probably still want to move the canonical_eh_spec up in
> build_cp_fntype_variant, and pass that to cp_check_qualified_type?

And compare the canonical spec directly from cp_check_qualified_type
instead of using comp_except_specs?  Then IIUC for

  void f() throw(int);
  void g() throw(char);

we'd give g the same function type as f, which seems wrong?


> 
> > Like so?
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]
> > 
> > Here the member functions QList::g and QList::h are given the same
> > function type since their exception specifications are equivalent
> > according to cp_tree_equal.  In doing so however this means that the
> > type of QList::h refers to a function parameter from QList::g, which
> > ends up confusing modules streaming.
> > 
> > I'm not sure if modules can be fixed to handle this situation, but
> > regardless it seems weird in principle that a function parameter can
> > escape in such a way.  The analogous situation with a trailing return
> > type and decltype
> > 
> >auto g(QList ) -> decltype(f(other));
> >auto h(QList ) -> decltype(f(other));
> > 
> > behaves better because we don't canonicalize decltype, and so the
> > function types of g and h are non-canonical and therefore not shared.
> > 
> > In light of this, it seems natural to treat function types with complex
> > eh specs as non-canonical as well so that each such function declaration
> > is given a unique function/method type node.  The main benefit of type
> > canonicalization is to speed up repeated type comparisons, but it should
> > rare for us to repeatedly compare two otherwise compatible function
> > types with complex exception specifications, so foregoing canonicalization
> > should not cause any problems.
> > 
&

Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
On Tue, 21 May 2024, Jason Merrill wrote:

> On 5/21/24 17:27, Patrick Palka wrote:
> > On Tue, 21 May 2024, Jason Merrill wrote:
> > 
> > > On 5/21/24 15:36, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > OK for trunk?
> > > > 
> > > > Alternatively, I considered fixing this by incrementing
> > > > comparing_specializations around the call to comp_except_specs in
> > > > cp_check_qualified_type, but generally for types whose identity
> > > > depends on whether comparing_specializations is set we need to
> > > > use structural equality anyway IIUC.
> > > 
> > > Why not both?
> > 
> > I figured the latter change isn't necessary/observable since
> > comparing_specializations would only make a difference for complex
> > exception specifications, and with this patch we won't even call
> > cp_check_qualified_type on a complex eh spec.
> 
> My concern is that if we're building a function type multiple times with the
> same noexcept-spec, this patch would mean creating multiple equivalent
> function types instead of reusing one already created for the same function.
> 
> > > > +  bool complex_p = (cr && cr != noexcept_true_spec
> > > > +   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> > > 
> > > Why treat unparsed specs differently from parsed ones?
> > 
> > Unparsed specs are unique according to cp_tree_equal, so in turn
> > function types with unparsed specs are unique, so it should be safe to
> > treat such types as canonical.  I'm not sure if this optimization
> > matters though; I'm happy to remove this case.
> 
> The idea that this optimization could make a difference raised the concern
> above.

Aha, makes sense.  To that end it seems we could strengthen the ce_exact
in comp_except_specs to require == instead of cp_tree_equal equality
when comparing two noexcept-specs; the only ce_exact callers are
cp_check_qualified_type and cxx_type_hash_eq, which should be fine with
that strengthening.  This way, we at least do try to reuse a variant if
the (complex or unparsed) noexcept-spec is exactly the same.

Like so?

-- >8 --

Subject: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

Here the member functions QList::g and QList::h are given the same
function type since their exception specifications are equivalent
according to cp_tree_equal.  In doing so however this means that the
type of QList::h refers to a function parameter from QList::g, which
ends up confusing modules streaming.

I'm not sure if modules can be fixed to handle this situation, but
regardless it seems weird in principle that a function parameter can
escape in such a way.  The analogous situation with a trailing return
type and decltype

  auto g(QList ) -> decltype(f(other));
  auto h(QList ) -> decltype(f(other));

behaves better because we don't canonicalize decltype, and so the
function types of g and h are non-canonical and therefore not shared.

In light of this, it seems natural to treat function types with complex
eh specs as non-canonical as well so that each such function declaration
is given a unique function/method type node.  The main benefit of type
canonicalization is to speed up repeated type comparisons, but it should
rare for us to repeatedly compare two otherwise compatible function
types with complex exception specifications, so foregoing canonicalization
should not cause any problems.

To that end, this patch strengthens the ce_exact case of comp_except_specs
to require identity instead of equivalence of the exception specification
so that build_cp_fntype_variant doesn't reuse a variant when it shouldn't.
And in build_cp_fntype_variant we need to use structural equality for types
with a complex eh spec.  In turn we could simplify the code responsible
for adjusting unparsed eh spec variants.

PR c++/115159

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Always use structural
equality for types with a complex exception specification.
(fixup_deferred_exception_variants): Always use structural
equality for adjusted variants.
* typeck.cc (comp_except_specs): Require == instead of
cp_tree_equal for noexcept-spec comparison in the ce_exact case.

gcc/testsuite/ChangeLog:

* g++.dg/modules/noexcept-2_a.H: New test.
* g++.dg/modules/noexcept-2_b.C: New test.
---
 gcc/cp/tree.cc  | 47 +
 gcc/cp/typeck.cc|  4 +-
 gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++
 gcc/testsuite/g++.dg/modules/noexcept-2_b.C |  4 ++
 4 files changed, 41 insertions(+), 38 deletions(-)
 create mode 100644 gc

Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
On Tue, 21 May 2024, Patrick Palka wrote:

> On Tue, 21 May 2024, Jason Merrill wrote:
> 
> > On 5/21/24 15:36, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > Alternatively, I considered fixing this by incrementing
> > > comparing_specializations around the call to comp_except_specs in
> > > cp_check_qualified_type, but generally for types whose identity
> > > depends on whether comparing_specializations is set we need to
> > > use structural equality anyway IIUC.
> > 
> > Why not both?
> 
> I figured the latter change isn't necessary/observable since
> comparing_specializations would only make a difference for complex
> exception specifications, and with this patch we won't even call
> cp_check_qualified_type on a complex eh spec.
> 
> > 
> > > +  bool complex_p = (cr && cr != noexcept_true_spec
> > > + && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> > 
> > Why treat unparsed specs differently from parsed ones?
> 
> Unparsed specs are unique according to cp_tree_equal, so in turn
> function types with unparsed specs are unique, so it should be safe to
> treat such types as canonical.  I'm not sure if this optimization
> matters though; I'm happy to remove this case.

FWIW if we do get rid of this case then I think in
fixup_deferred_exception_variants we can assert TYPE_STRUCTURAL_EQUALITY_P
is already set instead of having to set it.

> 
> > 
> > Jason
> > 
> > 
> 



Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
On Tue, 21 May 2024, Jason Merrill wrote:

> On 5/21/24 15:36, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk?
> > 
> > Alternatively, I considered fixing this by incrementing
> > comparing_specializations around the call to comp_except_specs in
> > cp_check_qualified_type, but generally for types whose identity
> > depends on whether comparing_specializations is set we need to
> > use structural equality anyway IIUC.
> 
> Why not both?

I figured the latter change isn't necessary/observable since
comparing_specializations would only make a difference for complex
exception specifications, and with this patch we won't even call
cp_check_qualified_type on a complex eh spec.

> 
> > +  bool complex_p = (cr && cr != noexcept_true_spec
> > +   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> 
> Why treat unparsed specs differently from parsed ones?

Unparsed specs are unique according to cp_tree_equal, so in turn
function types with unparsed specs are unique, so it should be safe to
treat such types as canonical.  I'm not sure if this optimization
matters though; I'm happy to remove this case.

> 
> Jason
> 
> 



[gcc r14-10226] c++: folding non-dep enumerator from current inst [PR115139]

2024-05-21 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:caf43cc9e5c0b3265b55e5a0dc77fc55e9618c77

commit r14-10226-gcaf43cc9e5c0b3265b55e5a0dc77fc55e9618c77
Author: Patrick Palka 
Date:   Tue May 21 15:54:10 2024 -0400

c++: folding non-dep enumerator from current inst [PR115139]

After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during
fold_non_dependent_expr for 'e1 | e2' below ultimately because we no
longer exit early when substituting the CONST_DECLs for e1 and e2 with
args=NULL_TREE and instead proceed to substitute the class context A
(also with args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion
(due to processing_template_decl being cleared).

Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type
removal r15-123-gf04dc89a991ddc since it changed the CONST_DECL case of
tsubst_expr to use tsubst to substitute the context, which short circuits
for empty args and so avoids the ICE.

This patch fixes this ICE for GCC 14 by narrowly restoring the early exit
for empty args that would've happened in tsubst_copy when substituting an
enumerator CONST_DECL.  We might as well apply this to trunk too, as a
small optimization.

PR c++/115139

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Exit early if args
is empty.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent33.C: New test.

Reviewed-by: Marek Polacek 
Reviewed-by: Jason Merrill 
(cherry picked from commit f0c0bced62b9c728ed1e672747aa234d918da22c)

Diff:
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/template/non-dependent33.C | 13 +
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e9882f2a3e0..ba47620ec59 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21524,7 +21524,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
if (DECL_TEMPLATE_PARM_P (t))
  RETURN (RECUR (DECL_INITIAL (t)));
-   if (!uses_template_parms (DECL_CONTEXT (t)))
+   if (!args || !uses_template_parms (DECL_CONTEXT (t)))
  RETURN (t);
 
/* Unfortunately, we cannot just call lookup_name here.
diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C 
b/gcc/testsuite/g++.dg/template/non-dependent33.C
new file mode 100644
index 000..ea5b41fba93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent33.C
@@ -0,0 +1,13 @@
+// PR c++/115139
+// { dg-do compile { target c++11 } }
+
+template
+class A {
+  enum E {
+e1 = 1,
+e2 = 2,
+e3 = e1 | e2,
+  };
+};
+
+template class A;


[gcc r15-759] c++: folding non-dep enumerator from current inst [PR115139]

2024-05-21 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:f0c0bced62b9c728ed1e672747aa234d918da22c

commit r15-759-gf0c0bced62b9c728ed1e672747aa234d918da22c
Author: Patrick Palka 
Date:   Tue May 21 15:54:10 2024 -0400

c++: folding non-dep enumerator from current inst [PR115139]

After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during
fold_non_dependent_expr for 'e1 | e2' below ultimately because we no
longer exit early when substituting the CONST_DECLs for e1 and e2 with
args=NULL_TREE and instead proceed to substitute the class context A
(also with args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion
(due to processing_template_decl being cleared).

Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type
removal r15-123-gf04dc89a991ddc since it changed the CONST_DECL case of
tsubst_expr to use tsubst to substitute the context, which short circuits
for empty args and so avoids the ICE.

This patch fixes this ICE for GCC 14 by narrowly restoring the early exit
for empty args that would've happened in tsubst_copy when substituting an
enumerator CONST_DECL.  We might as well apply this to trunk too, as a
small optimization.

PR c++/115139

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Exit early if args
is empty.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent33.C: New test.

Reviewed-by: Marek Polacek 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/template/non-dependent33.C | 13 +
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e77c48e463e..a95ce6eb3da 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21519,7 +21519,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
if (DECL_TEMPLATE_PARM_P (t))
  RETURN (RECUR (DECL_INITIAL (t)));
-   if (!uses_template_parms (DECL_CONTEXT (t)))
+   if (!args || !uses_template_parms (DECL_CONTEXT (t)))
  RETURN (t);
 
/* Unfortunately, we cannot just call lookup_name here.
diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C 
b/gcc/testsuite/g++.dg/template/non-dependent33.C
new file mode 100644
index 000..ea5b41fba93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent33.C
@@ -0,0 +1,13 @@
+// PR c++/115139
+// { dg-do compile { target c++11 } }
+
+template
+class A {
+  enum E {
+e1 = 1,
+e2 = 2,
+e3 = e1 | e2,
+  };
+};
+
+template class A;


[PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

Alternatively, I considered fixing this by incrementing
comparing_specializations around the call to comp_except_specs in
cp_check_qualified_type, but generally for types whose identity
depends on whether comparing_specializations is set we need to
use structural equality anyway IIUC.

Or maybe it isn't right to fix this outside of modules, and we should
instead make modules cope with this cross-function function parameter
reference?  I briefly tried looking into this but didn't get very far.

-- >8 --

Here the member functions QList::g and QList::h are given the same
function type since their exception specifications are equivalent
according to cp_tree_equal.  In doing so however this means that the
type of QList::h refers to a function parameter from QList::g, which
ends up confusing modules streaming.

I'm not sure if modules can be fixed to handle this situation, but
regardless it seems weird in principle that a function parameter can
escape in such a way.  The analogous situation with a trailing return
type and decltype

  auto g(QList ) -> decltype(f(other));
  auto h(QList ) -> decltype(f(other));

behaves better because we don't canonicalize decltype, and so the
function types of g and h are non-canonical and therefore not shared.

In light of this, it seems natural to treat function types with complex
eh specs as non-canonical as well so that each such function declaration
is given a unique function/method type node.  The main benefit of type
canonicalization is to speed up repeated type comparisons, but it should
rare for us to repeatedly compare two otherwise compatible function
types with complex exception specifications, so foregoing canonicalization
should be harmless IIUC.  On the other hand this change simplifies the
code responsible for adjusting unparsed eh spec variants.

PR c++/115159

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Don't reuse a variant with
a complex exception specification.  Always use structural
equality in that case.
(fixup_deferred_exception_variants): Always use structural
equality for adjusted variants.

gcc/testsuite/ChangeLog:

* g++.dg/modules/noexcept-2_a.H: New test.
* g++.dg/modules/noexcept-2_b.C: New test.
---
 gcc/cp/tree.cc  | 70 +++--
 gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++
 gcc/testsuite/g++.dg/modules/noexcept-2_b.C |  4 ++
 3 files changed, 51 insertions(+), 47 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/noexcept-2_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/noexcept-2_b.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 9d37d255d8d..7987c01520d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2761,16 +2761,27 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 {
   cp_cv_quals type_quals = TYPE_QUALS (type);
 
-  if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
-return type;
+  /* Canonicalize the exception specification.  */
+  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
+  /* For a complex exception specification, always create a distinct
+ non-canonical variant for simplicity.  This also prevents noexcept-specs
+ that are in terms of a function parameter from getting shared with an
+ another function.  */
+  bool complex_p = (cr && cr != noexcept_true_spec
+   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
+  if (!complex_p)
+{
+  if (cp_check_qualified_type (type, type, type_quals, rqual, raises, 
late))
+   return type;
 
-  tree v = TYPE_MAIN_VARIANT (type);
-  for (; v; v = TYPE_NEXT_VARIANT (v))
-if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
-  return v;
+  tree v = TYPE_MAIN_VARIANT (type);
+  for (; v; v = TYPE_NEXT_VARIANT (v))
+   if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
+ return v;
+}
 
   /* Need to build a new variant.  */
-  v = build_variant_type_copy (type);
+  tree v = build_variant_type_copy (type);
   if (!TYPE_DEPENDENT_P (v))
 /* We no longer know that it's not type-dependent.  */
 TYPE_DEPENDENT_P_VALID (v) = false;
@@ -2791,10 +2802,7 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
   break;
 }
 
-  /* Canonicalize the exception specification.  */
-  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
-
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
+  if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_p)
 /* Propagate structural equality. */
 SET_TYPE_STRUCTURAL_EQUALITY (v);
   else if (TYPE_CANONICAL (type) != type || cr != raises || late)
@@ -2812,55 +2820,23 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 /* TYPE is a function or method type with a deferred exception
specification that has been parsed to RAISES.  

[gcc r14-10221] c++: aggregate CTAD w/ paren init and bases [PR115114]

2024-05-20 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:a9837934203d41c96b5cf05e34f68c0d3311c973

commit r14-10221-ga9837934203d41c96b5cf05e34f68c0d3311c973
Author: Patrick Palka 
Date:   Fri May 17 09:02:52 2024 -0400

c++: aggregate CTAD w/ paren init and bases [PR115114]

During aggregate CTAD with paren init, we're accidentally overlooking
base classes since TYPE_FIELDS of a template type doesn't contain
corresponding base fields.  So we need to consider them separately.

PR c++/115114

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Consider bases in the paren init case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr15.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2)

Diff:
---
 gcc/cp/pt.cc   |  7 +++
 .../g++.dg/cpp2a/class-deduction-aggr15.C  | 23 ++
 2 files changed, 30 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b5c494e8d15e..e9882f2a3e0a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30205,6 +30205,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
+  for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
+   {
+ if (!len)
+   break;
+ parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
+ --len;
+   }
   for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
new file mode 100644
index ..16dc0f52b64c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
@@ -0,0 +1,23 @@
+// PR c++/115114
+// { dg-do compile { target c++20 } }
+
+struct X {} x;
+struct Y {} y;
+
+template
+struct A : T {
+  U m;
+};
+
+using ty1 = decltype(A{x, 42}); // OK
+using ty1 = decltype(A(x, 42)); // OK, used to fail
+using ty1 = A;
+
+template
+struct B : T, V {
+  U m = 42;
+};
+
+using ty2 = decltype(B{x, y}); // OK
+using ty2 = decltype(B(x, y)); // OK, used to fail
+using ty2 = B;


[gcc r14-10220] c++: lvalueness of non-dependent assignment expr [PR114994]

2024-05-20 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:b3399b445ba7495b0479d43f2389e64d48de870e

commit r14-10220-gb3399b445ba7495b0479d43f2389e64d48de870e
Author: Patrick Palka 
Date:   Tue May 14 22:55:16 2024 -0400

c++: lvalueness of non-dependent assignment expr [PR114994]

r14-4111-g6e92a6a2a72d3b made us check non-dependent simple assignment
expressions ahead of time and give them a type, as was already done for
compound assignments.  Unlike for compound assignments however, if a
simple assignment resolves to an operator overload we represent it as a
(typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload.
(I reckoned this was at worst a pessimization -- we'll just have to repeat
overload resolution at instantiatiation time.)

But this turns out to break the below testcase ultimately because
MODOP_EXPR (of non-reference type) is always treated as an lvalue
according to lvalue_kind, which is incorrect for the MODOP_EXPR
representing x=42.

We can fix this by representing such class assignment expressions as
CALL_EXPRs as well, but this turns out to require some tweaking of our
-Wparentheses warning logic and may introduce other fallout making it
unsuitable for backporting.

So this patch instead fixes lvalue_kind to consider the type of a
MODOP_EXPR representing a class assignment.

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : For a class
assignment, consider the result type.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit c6cc6d4741a880109c4e0e64d5a189687fb526f6)

Diff:
---
 gcc/cp/tree.cc  |  5 -
 gcc/testsuite/g++.dg/template/non-dependent32.C | 18 ++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe8179..9d37d255d8d5 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,7 +275,10 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
-  return clk_ordinary;
+  if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   goto default_;
+  else
+   return clk_ordinary;
 
 case MODIFY_EXPR:
 case TYPEID_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index ..54252c7dfaf9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int main() {
+  g();
+}


[PATCH] c++: folding non-dep enumerator from current inst [PR115139]

2024-05-17 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/14?

-- >8 --

After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during
fold_non_dependent_expr for 'e1 | e2' ultimately because we no longer exit
early when substituting the CONST_DECLs for e1 and e2 with args=NULL_TREE,
during which we try substituting the class context A (also with
args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion (due to
processing_template_decl being cleared).

Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type
removal r15-123-gf04dc89a991ddc since it made the CONST_DECL case of
tsubst_expr use tsubst to substitute the context, which does short circuit
for empty args and so avoids the ICE.

This patch fixes this ICE for GCC 14 by narrowly restoring the early exit
for empty args that was present in tsubst_copy when substituting an
enumerator CONST_DECL.  We might as well apply this to trunk too, as a
very minor optimization.

PR c++/115139

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Exit early if args
is empty.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent33.C: New test.
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/template/non-dependent33.C | 11 +++
 2 files changed, 12 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent33.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e946..e185e3d8941 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21519,7 +21519,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
if (DECL_TEMPLATE_PARM_P (t))
  RETURN (RECUR (DECL_INITIAL (t)));
-   if (!uses_template_parms (DECL_CONTEXT (t)))
+   if (!args || !uses_template_parms (DECL_CONTEXT (t)))
  RETURN (t);
 
/* Unfortunately, we cannot just call lookup_name here.
diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C 
b/gcc/testsuite/g++.dg/template/non-dependent33.C
new file mode 100644
index 000..2f1dd8a214c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent33.C
@@ -0,0 +1,11 @@
+// PR c++/115139
+// { dg-do compile { target c++11 } }
+
+template
+class A {
+  enum E {
+e1 = 1,
+e2 = 2,
+e3 = e1 | e2,
+  };
+};
-- 
2.45.1.204.gd8ab1d464d



[gcc r15-630] c++: aggregate CTAD w/ paren init and bases [PR115114]

2024-05-17 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2

commit r15-630-g5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2
Author: Patrick Palka 
Date:   Fri May 17 09:02:52 2024 -0400

c++: aggregate CTAD w/ paren init and bases [PR115114]

During aggregate CTAD with paren init, we're accidentally overlooking
base classes since TYPE_FIELDS of a template type doesn't contain
corresponding base fields.  So we need to consider them separately.

PR c++/115114

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Consider bases in the paren init case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr15.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc   |  7 +++
 .../g++.dg/cpp2a/class-deduction-aggr15.C  | 23 ++
 2 files changed, 30 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e946d..e77c48e463e2 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30200,6 +30200,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
+  for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
+   {
+ if (!len)
+   break;
+ parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
+ --len;
+   }
   for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
new file mode 100644
index ..16dc0f52b64c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
@@ -0,0 +1,23 @@
+// PR c++/115114
+// { dg-do compile { target c++20 } }
+
+struct X {} x;
+struct Y {} y;
+
+template
+struct A : T {
+  U m;
+};
+
+using ty1 = decltype(A{x, 42}); // OK
+using ty1 = decltype(A(x, 42)); // OK, used to fail
+using ty1 = A;
+
+template
+struct B : T, V {
+  U m = 42;
+};
+
+using ty2 = decltype(B{x, y}); // OK
+using ty2 = decltype(B(x, y)); // OK, used to fail
+using ty2 = B;


[PATCH] c++: paren aggr CTAD with base classes [PR115114]

2024-05-16 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk and perhaps 14?

-- >8 --

We're accidentally ignoring base classes during parenthesized aggregate
CTAD because the TYPE_FIELDS of a template type doesn't contain bases,
so we need to consider them separately.

PR c++/115114

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Consider base classes in the paren
init case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr15.C: New test.
---
 gcc/cp/pt.cc  |  7 ++
 .../g++.dg/cpp2a/class-deduction-aggr15.C | 23 +++
 2 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d83f530ac8d..54d74989903 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30202,6 +30202,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
+  for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
+   {
+ if (!len)
+   break;
+ parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
+ --len;
+   }
   for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
new file mode 100644
index 000..16dc0f52b64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
@@ -0,0 +1,23 @@
+// PR c++/115114
+// { dg-do compile { target c++20 } }
+
+struct X {} x;
+struct Y {} y;
+
+template
+struct A : T {
+  U m;
+};
+
+using ty1 = decltype(A{x, 42}); // OK
+using ty1 = decltype(A(x, 42)); // OK, used to fail
+using ty1 = A;
+
+template
+struct B : T, V {
+  U m = 42;
+};
+
+using ty2 = decltype(B{x, y}); // OK
+using ty2 = decltype(B(x, y)); // OK, used to fail
+using ty2 = B;
-- 
2.45.1.190.g19fe900cfc



[PATCH] c++: represent all class non-dep assignments as CALL_EXPR

2024-05-15 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linu-xgnu, does this look OK
for trunk?

-- >8 --

Non-dependent compound assignment expressions are currently represented
as CALL_EXPR to the selected operator@= overload.  Non-dependent simple
assignments on the other hand are still represented as MODOP_EXPR, which
doesn't hold on to the selected overload.

That we need to remember the selected operator@= overload ahead of time
is a correctness thing, because they can be declared at namespace scope
and we don't want to consider later-declared namespace scope overloads
at instantiation time.  This doesn't apply to simple operator= because
it can only be declared at class scope, so it's fine to repeat the name
lookup and overload resolution at instantiation time.  But it still
seems desirable for sake of QoI to also avoid this repeated name lookup
and overload resolution for simple assignments along the lines of
r12-6075-g2decd2cabe5a4f.

To that end, this patch makes us represent non-dependent simple
assignments as CALL_EXPR to the selected operator= overload rather than
as MODOP_EXPR.  In order for is_assignment_op_expr_p to recognize such
CALL_EXPR as an assignment expression, cp_get_fndecl_from_callee needs
to look through templated COMPONENT_REF callee corresponding to a member
function call, otherwise ahead of time -Wparentheses warnings stop
working (e.g. g++.dg/warn/Wparentheses-{32,33}.C).

gcc/cp/ChangeLog:

* call.cc (build_new_op): Pass 'overload' to
cp_build_modify_expr.
* cp-tree.h (cp_build_modify_expr): New overload that
takes a tree* out-parameter.
* pt.cc (tsubst_expr) : Propagate
OPT_Wparentheses warning suppression to the result.
* cvt.cc (cp_get_fndecl_from_callee): Use maybe_get_fns
to extract the FUNCTION_DECL from a callee.
* semantics.cc (is_assignment_op_expr_p): Also recognize
templated operator expressions represented as a CALL_EXPR
to operator=.
* typeck.cc (cp_build_modify_expr): Add 'overload'
out-parameter and pass it to build_new_op.
(build_x_modify_expr): Pass 'overload' to cp_build_modify_expr.
---
 gcc/cp/call.cc   |  2 +-
 gcc/cp/cp-tree.h |  3 +++
 gcc/cp/cvt.cc|  5 +++--
 gcc/cp/pt.cc |  2 ++
 gcc/cp/typeck.cc | 18 ++
 5 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index e058da7735f..e3d4cf8949d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
code, int flags,
   switch (code)
 {
 case MODIFY_EXPR:
-  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
+  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, complain);
 
 case INDIRECT_REF:
   return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9a8c8659157..1e565086e80 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8267,6 +8267,9 @@ extern tree cp_build_c_cast   
(location_t, tree, tree,
 extern cp_expr build_x_modify_expr (location_t, tree,
 enum tree_code, tree,
 tree, tsubst_flags_t);
+extern tree cp_build_modify_expr   (location_t, tree,
+enum tree_code, tree,
+tree *, tsubst_flags_t);
 extern tree cp_build_modify_expr   (location_t, tree,
 enum tree_code, tree,
 tsubst_flags_t);
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index db086c017e8..2f4c0f88694 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1015,8 +1015,9 @@ cp_get_fndecl_from_callee (tree fn, bool fold /* = true 
*/)
   return f;
 };
 
-  if (TREE_CODE (fn) == FUNCTION_DECL)
-return fn_or_local_alias (fn);
+  if (tree f = maybe_get_fns (fn))
+if (TREE_CODE (f) == FUNCTION_DECL)
+  return fn_or_local_alias (f);
   tree type = TREE_TYPE (fn);
   if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
 return NULL_TREE;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e946..d83f530ac8d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21093,6 +21093,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
  /* This also suppresses -Wredundant-move.  */
  suppress_warning (ret, OPT_Wpessimizing_move);
+   if (warning_suppressed_p (t, OPT_Wparentheses))
+ suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
  }
 
RETURN (ret);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5f16994300f..75b696e32e0 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9421,7 +9421,7 

Re: [PATCH v3] c++: Fix auto deduction for template specialization scopes [PR114915]

2024-05-15 Thread Patrick Palka
On Wed, 15 May 2024, Patrick Palka wrote:

> 
> On Fri, 10 May 2024, Seyed Sajad Kahani wrote:
> 
> > This patch resolves PR114915 by replacing the logic that fills in the 
> > missing levels in do_auto_deduction in cp/pt.cc.
> > The new approach now trims targs if the depth of targs is deeper than 
> > desired (this will only happen in specific contexts), and still fills targs 
> > with empty layers if it has fewer depths than expected.
> 
> The logic looks good to me, thanks!  Note that as per
> https://gcc.gnu.org/contribute.html patches need a ChangeLog entry in
> the commit message, for example let's use:
> 
>   PR c++/114915
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (do_auto_deduction): Handle excess outer template
>   arguments during constrained auto satisfaction.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-placeholder14.C: New test.
>   * g++.dg/cpp2a/concepts-placeholder15.C: New test.
>   * g++.dg/cpp2a/concepts-placeholder16.C: New test.
> 
> Jason, what do you think?

... now sent to the correct email, sorry for the spam

> 
> > ---
> >  gcc/cp/pt.cc  | 20 ---
> >  .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
> >  .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
> >  .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
> >  4 files changed, 83 insertions(+), 4 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 3b2106dd3..479b2a5bd 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree 
> > auto_node,
> > full_targs = add_outermost_template_args (tmpl, full_targs);
> >full_targs = add_to_template_args (full_targs, targs);
> >  
> > +  int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> > +  int have = TMPL_ARGS_DEPTH (full_targs);
> > +
> > +  if (want < have)
> > +   {
> > + // if a constrained auto is declared in an explicit specialization
> > + gcc_assert (context == adc_variable_type || context == adc_return_type
> > + || context == adc_decomp_type);
> > + tree trimmed_full_args = get_innermost_template_args
> > +   (full_targs, want);
> > + full_targs = trimmed_full_args;
> > +   }
> > +  
> >/* HACK: Compensate for callers not always communicating all levels 
> > of
> >  outer template arguments by filling in the outermost missing levels
> >  with dummy levels before checking satisfaction.  We'll still crash
> > @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree 
> > auto_node,
> >  these missing levels, but this hack otherwise allows us to handle a
> >  large subset of possible constraints (including all non-dependent
> >  constraints).  */
> > -  if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> > -   - TMPL_ARGS_DEPTH (full_targs)))
> > +  if (want > have)
> > {
> > - tree dummy_levels = make_tree_vec (missing_levels);
> > - for (int i = 0; i < missing_levels; ++i)
> > + tree dummy_levels = make_tree_vec (want - have);
> > + for (int i = 0; i < want - have; ++i)
> > TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> >   full_targs = add_to_template_args (dummy_levels, full_targs);
> > }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C 
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > new file mode 100644
> > index 0..fcdbd7608
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > @@ -0,0 +1,19 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template
> > +concept C = __is_same(T, int);
> > +
> > +template
> > +void f() {
> > +}
> > +
> > +template<>
> > +void f() {
> > +  C auto x = 1;
> > +}
> > +
> > +int main() {
> > +  f();
> > +  return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C 
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > new file mode 100644
> > index 0..b4f73f407
> > --- /dev/

Re: [PATCH v3] c++: Fix auto deduction for template specialization scopes [PR114915]

2024-05-15 Thread Patrick Palka


On Fri, 10 May 2024, Seyed Sajad Kahani wrote:

> This patch resolves PR114915 by replacing the logic that fills in the missing 
> levels in do_auto_deduction in cp/pt.cc.
> The new approach now trims targs if the depth of targs is deeper than desired 
> (this will only happen in specific contexts), and still fills targs with 
> empty layers if it has fewer depths than expected.

The logic looks good to me, thanks!  Note that as per
https://gcc.gnu.org/contribute.html patches need a ChangeLog entry in
the commit message, for example let's use:

PR c++/114915

gcc/cp/ChangeLog:

* pt.cc (do_auto_deduction): Handle excess outer template
arguments during constrained auto satisfaction.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.

Jason, what do you think?

> ---
>  gcc/cp/pt.cc  | 20 ---
>  .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
>  .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
>  .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
>  4 files changed, 83 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..479b2a5bd 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>   full_targs = add_outermost_template_args (tmpl, full_targs);
>full_targs = add_to_template_args (full_targs, targs);
>  
> +  int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> +  int have = TMPL_ARGS_DEPTH (full_targs);
> +
> +  if (want < have)
> + {
> +   // if a constrained auto is declared in an explicit specialization
> +   gcc_assert (context == adc_variable_type || context == adc_return_type
> +   || context == adc_decomp_type);
> +   tree trimmed_full_args = get_innermost_template_args
> + (full_targs, want);
> +   full_targs = trimmed_full_args;
> + }
> +  
>/* HACK: Compensate for callers not always communicating all levels of
>outer template arguments by filling in the outermost missing levels
>with dummy levels before checking satisfaction.  We'll still crash
> @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>these missing levels, but this hack otherwise allows us to handle a
>large subset of possible constraints (including all non-dependent
>constraints).  */
> -  if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> +  if (want > have)
>   {
> -   tree dummy_levels = make_tree_vec (missing_levels);
> -   for (int i = 0; i < missing_levels; ++i)
> +   tree dummy_levels = make_tree_vec (want - have);
> +   for (int i = 0; i < want - have; ++i)
>   TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> full_targs = add_to_template_args (dummy_levels, full_targs);
>   }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 0..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept C = __is_same(T, int);
> +
> +template
> +void f() {
> +}
> +
> +template<>
> +void f() {
> +  C auto x = 1;
> +}
> +
> +int main() {
> +  f();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 0..b4f73f407
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,15 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept C = __is_same(T, U);
> +
> +template
> +int x = 0;
> +
> +template<>
> +C auto x = 1.0;
> +
> +int main() {
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 0..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept C = __is_same(T, U);
> +
> +template
> +struct A
> +{ 
> +template
> +void f() {
> +}
> +};
> + 
> +template<>
> +template<>
> +void A::f() {
> +  C auto x = 1;
> +}
> +
> +template<>
> +template
> +void 

[gcc r15-498] c++: lvalueness of non-dependent assignment expr [PR114994]

2024-05-14 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:c6cc6d4741a880109c4e0e64d5a189687fb526f6

commit r15-498-gc6cc6d4741a880109c4e0e64d5a189687fb526f6
Author: Patrick Palka 
Date:   Tue May 14 22:55:16 2024 -0400

c++: lvalueness of non-dependent assignment expr [PR114994]

r14-4111-g6e92a6a2a72d3b made us check non-dependent simple assignment
expressions ahead of time and give them a type, as was already done for
compound assignments.  Unlike for compound assignments however, if a
simple assignment resolves to an operator overload we represent it as a
(typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload.
(I reckoned this was at worst a pessimization -- we'll just have to repeat
overload resolution at instantiatiation time.)

But this turns out to break the below testcase ultimately because
MODOP_EXPR (of non-reference type) is always treated as an lvalue
according to lvalue_kind, which is incorrect for the MODOP_EXPR
representing x=42.

We can fix this by representing such class assignment expressions as
CALL_EXPRs as well, but this turns out to require some tweaking of our
-Wparentheses warning logic and may introduce other fallout making it
unsuitable for backporting.

So this patch instead fixes lvalue_kind to consider the type of a
MODOP_EXPR representing a class assignment.

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : For a class
assignment, consider the result type.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc  |  5 -
 gcc/testsuite/g++.dg/template/non-dependent32.C | 18 ++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe8179..9d37d255d8d5 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,7 +275,10 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
-  return clk_ordinary;
+  if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   goto default_;
+  else
+   return clk_ordinary;
 
 case MODIFY_EXPR:
 case TYPEID_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index ..54252c7dfaf9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int main() {
+  g();
+}


[gcc r13-8767] c++: build_extra_args recapturing local specs [PR114303]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:47cac09307874ff1d640392e3d986453f34f7bcb

commit r13-8767-g47cac09307874ff1d640392e3d986453f34f7bcb
Author: Patrick Palka 
Date:   Thu Apr 11 10:16:41 2024 -0400

c++: build_extra_args recapturing local specs [PR114303]

r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
first so that we prefer processing a local specialization in an evaluated
context even if its first use is in an unevaluated context.  But this
means we need to avoid walking a tree that already has extra args/specs
saved because the list of saved specs appears to be an evaluated
context which we'll now walk first.  It seems then that we should be
calculating the saved specs from scratch each time, rather than
potentially walking the saved specs list from an earlier partial
instantiation when calling build_extra_args a second time around.

PR c++/114303

gcc/cp/ChangeLog:

* constraint.cc (tsubst_requires_expr): Clear
REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
* pt.cc (tree_extra_args): Define.
(extract_locals_r): Assert *_EXTRA_ARGS is empty.
(tsubst_stmt) : Clear IF_SCOPE on the new
IF_STMT.  Call build_extra_args on the new IF_STMT instead
of t which might already have IF_STMT_EXTRA_ARGS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/constexpr-if-lambda6.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit b262b17636e47ae969a74f16e86ccb00678d5e88)

Diff:
---
 gcc/cp/constraint.cc  |  1 +
 gcc/cp/pt.cc  | 31 ++-
 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C | 16 
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 83df57dc6fd7..67fe2ae17cd8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2370,6 +2370,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
 matching or dguide constraint rewriting), in which case we need
 to partially substitute.  */
   t = copy_node (t);
+  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
   return t;
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fa660fcf49ee..3af705c647a0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3861,6 +3861,24 @@ has_extra_args_mechanism_p (const_tree t)
  && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS  */
 }
 
+/* Return *_EXTRA_ARGS of the given supported tree T.  */
+
+static tree&
+tree_extra_args (tree t)
+{
+  gcc_checking_assert (has_extra_args_mechanism_p (t));
+
+  if (PACK_EXPANSION_P (t))
+return PACK_EXPANSION_EXTRA_ARGS (t);
+  else if (TREE_CODE (t) == REQUIRES_EXPR)
+return REQUIRES_EXPR_EXTRA_ARGS (t);
+  else if (TREE_CODE (t) == IF_STMT
+  && IF_STMT_CONSTEXPR_P (t))
+return IF_STMT_EXTRA_ARGS (t);
+
+  gcc_unreachable ();
+}
+
 /* Structure used to track the progress of find_parameter_packs_r.  */
 struct find_parameter_pack_data
 {
@@ -13185,6 +13203,16 @@ extract_locals_r (tree *tp, int *walk_subtrees, void 
*data_)
 /* Remember local typedefs (85214).  */
 tp = _NAME (*tp);
 
+  if (has_extra_args_mechanism_p (*tp))
+/* Assert *_EXTRA_ARGS is empty, because we don't want to walk it and
+   potentially see a previously captured local in an evaluated context
+   that's really only used in an unevaluated context (PR114303).  This
+   means callers of build_extra_args need to clear *_EXTRA_ARGS of the
+   outermost tree.  Nested *_EXTRA_ARGS should naturally be empty since
+   the outermost (extra-args) tree will intercept any substitution before
+   a nested tree can.  */
+gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE);
+
   if (TREE_CODE (*tp) == DECL_EXPR)
 {
   tree decl = DECL_EXPR_DECL (*tp);
@@ -19189,10 +19217,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 of the constexpr if is still dependent.  Don't substitute into the
 branches now, just remember the template arguments.  */
  do_poplevel (IF_SCOPE (stmt));
+ IF_SCOPE (stmt) = NULL_TREE;
  IF_COND (stmt) = IF_COND (t);
  THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
  ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
- IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+ IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
  add_stmt (stmt);
  break;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
new file mode 100644
index ..038c2a41210f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
@@ -0

[gcc r15-438] c++: replace tf_norm with a local flag

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:67476ba8adb432033993f429b1aa4ee5689fa046

commit r15-438-g67476ba8adb432033993f429b1aa4ee5689fa046
Author: Patrick Palka 
Date:   Mon May 13 15:46:55 2024 -0400

c++: replace tf_norm with a local flag

The tf_norm flag controlling whether to build diagnostic information
during constraint normalization doesn't need to be a global tsubst flag,
and is confusingly named.  This patch replaces it with a boolean flag
local to normalization.

gcc/cp/ChangeLog:

* constraint.cc (norm_info::norm_info): Take a bool instead of
tsubst_flags_t.
(norm_info::generate_diagnostics): Turn this predicate function
into a bool data member.
(normalize_logical_operation): Adjust after norm_info changes.
(normalize_concept_check): Likewise.
(normalize_atom): Likewise.
(get_normalized_constraints_from_info): Likewise.
(normalize_concept_definition): Likewise.
(normalize_constraint_expression): Likewise.
(normalize_placeholder_type_constraints): Likewise.
(satisfy_nondeclaration_constraints): Likewise.
* cp-tree.h (enum tsubst_flags): Remove tf_norm.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constraint.cc | 40 
 gcc/cp/cp-tree.h |  3 +--
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8679d3ce658d..ebf4255e546e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -622,33 +622,29 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
 
 struct norm_info : subst_info
 {
-  explicit norm_info (tsubst_flags_t cmp)
-: norm_info (NULL_TREE, cmp)
+  explicit norm_info (bool diag)
+: norm_info (NULL_TREE, diag)
   {}
 
   /* Construct a top-level context for DECL.  */
 
-  norm_info (tree in_decl, tsubst_flags_t complain)
-: subst_info (tf_warning_or_error | complain, in_decl)
+  norm_info (tree in_decl, bool diag)
+: subst_info (tf_warning_or_error, in_decl),
+  generate_diagnostics (diag)
   {
 if (in_decl)
   {
initial_parms = DECL_TEMPLATE_PARMS (in_decl);
-   if (generate_diagnostics ())
+   if (generate_diagnostics)
  context = build_tree_list (NULL_TREE, in_decl);
   }
 else
   initial_parms = current_template_parms;
   }
 
-  bool generate_diagnostics() const
-  {
-return complain & tf_norm;
-  }
-
   void update_context(tree expr, tree args)
   {
-if (generate_diagnostics ())
+if (generate_diagnostics)
   {
tree map = build_parameter_mapping (expr, args, ctx_parms ());
context = tree_cons (map, expr, context);
@@ -679,6 +675,10 @@ struct norm_info : subst_info
  template parameters of ORIG_DECL.  */
 
   tree initial_parms = NULL_TREE;
+
+  /* Whether to build diagnostic information during normalization.  */
+
+  bool generate_diagnostics;
 };
 
 static tree normalize_expression (tree, tree, norm_info);
@@ -693,7 +693,7 @@ normalize_logical_operation (tree t, tree args, tree_code 
c, norm_info info)
   tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
 
   /* Build a new info object for the constraint.  */
-  tree ci = info.generate_diagnostics()
+  tree ci = info.generate_diagnostics
 ? build_tree_list (t, info.context)
 : NULL_TREE;
 
@@ -777,7 +777,7 @@ normalize_concept_check (tree check, tree args, norm_info 
info)
   if (!norm_cache)
 norm_cache = hash_table::create_ggc (31);
   norm_entry *entry = nullptr;
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the normal form of the substituted concept-id (when not
 diagnosing).  */
@@ -831,7 +831,7 @@ normalize_atom (tree t, tree args, norm_info info)
   if (info.in_decl && concept_definition_p (info.in_decl))
 ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
 
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
 later can cheaply compare two atoms using just pointer equality.  */
@@ -910,7 +910,7 @@ get_normalized_constraints_from_info (tree ci, tree 
in_decl, bool diag = false)
 
   /* Substitution errors during normalization are fatal.  */
   ++processing_template_decl;
-  norm_info info (in_decl, diag ? tf_norm : tf_none);
+  norm_info info (in_decl, diag);
   tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci), info);
   --processing_template_decl;
 
@@ -1012,7 +1012,7 @@ normalize_concept_definition (tree tmpl, bool diag)
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
   ++processing_template_decl;
-  norm_info info (tmpl, diag ? tf_norm : tf_none);
+  norm_info info (tmpl, diag);
   tree norm = get_normalized_constraint

[gcc r13-8765] c++: constexpr union member access folding [PR114709]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:d3659e2dfcc6db83391cd2c6d70097cba35eb4b9

commit r13-8765-gd3659e2dfcc6db83391cd2c6d70097cba35eb4b9
Author: Patrick Palka 
Date:   Wed Apr 24 17:49:56 2024 -0400

c++: constexpr union member access folding [PR114709]

The object/offset canonicalization performed in cxx_fold_indirect_ref
is undesirable for union member accesses because it loses information
about the member being accessed which we may later need to diagnose an
inactive-member access.  So this patch restricts the canonicalization
accordingly.

PR c++/114709

gcc/cp/ChangeLog:

* constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset
canonicalization to RECORD_TYPE member accesses.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union8.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 0844170e9ef60a8b2f6fba6786672f30ce1c2749)

Diff:
---
 gcc/cp/constexpr.cc   | 3 +++
 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 
 2 files changed, 11 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index acb5496085bb..12dd9010148e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5547,6 +5547,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, 
location_t loc, tree type,
  more folding opportunities.  */
   auto canonicalize_obj_off = [] (tree& obj, tree& off) {
 while (TREE_CODE (obj) == COMPONENT_REF
+  /* We need to preserve union member accesses so that we can
+ later properly diagnose accessing the wrong member.  */
+  && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE
   && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
   {
tree field = TREE_OPERAND (obj, 1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
new file mode 100644
index ..34c264944b68
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
@@ -0,0 +1,8 @@
+// PR c++/114709
+// { dg-do compile { target c++11 } }
+
+struct T1 { int a, b; };
+struct T2 { int c; double d; };
+union U { T1 t1; T2 t2; };
+
+constexpr int v = U{{1,2}}.t2.*::c; // { dg-error "accessing 'U::t2'" }


[gcc r14-10201] c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:57cd8665fea4c339369a43be017583621aa82fed

commit r14-10201-g57cd8665fea4c339369a43be017583621aa82fed
Author: Patrick Palka 
Date:   Mon May 13 09:53:40 2024 -0400

c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

During maybe_aggr_guide with a nested class template and paren init,
like with list init we need to consider the generic template type rather
than the partially instantiated type since partial instantiations don't
have (partially instantiated) TYPE_FIELDS.  In turn we need to partially
substitute PARMs in the paren init case as well.  As a drive-by improvement
it seems better to use outer_template_args instead of DECL_TI_ARGS during
this partial substitution so that we lower instead of substitute the
innermost template parameters, which is generally more robust.

And during alias_ctad_tweaks with a nested class template, even though
the guides may be already partially instantiated we still need to
substitute the outermost arguments into its constraints.

PR c++/114974
PR c++/114901
PR c++/114903

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
the paren init case.  Hoist out partial substitution logic
to apply to the paren init case as well.
(alias_ctad_tweaks): Substitute outer template arguments into
a guide's constraints.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr14.C: New test.
* g++.dg/cpp2a/class-deduction-alias20.C: New test.
* g++.dg/cpp2a/class-deduction-alias21.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 6d31a370e26eeb950c326332633b3e8e84b6630b)

Diff:
---
 gcc/cp/pt.cc   | 39 --
 .../g++.dg/cpp2a/class-deduction-aggr14.C  | 11 ++
 .../g++.dg/cpp2a/class-deduction-alias20.C | 22 
 .../g++.dg/cpp2a/class-deduction-alias21.C | 38 +
 4 files changed, 93 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3b2106dd3f65..b5c494e8d15e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30201,26 +30201,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   if (init == error_mark_node)
return NULL_TREE;
   parms = collect_ctor_idx_types (init, parms);
-  /* If we're creating a deduction guide for a member class template,
-we've used the original template pattern type for the reshape_init
-above; this is done because we want PARMS to be a template parameter
-type, something that can be deduced when used as a function template
-parameter.  At this point the outer class template has already been
-partially instantiated (we deferred the deduction until the enclosing
-scope is non-dependent).  Therefore we have to partially instantiate
-PARMS, so that its template level is properly reduced and we don't get
-mismatches when deducing types using the guide with PARMS.  */
-  if (member_template_p)
-   {
- ++processing_template_decl;
- parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
- --processing_template_decl;
-   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
-  for (tree field = TYPE_FIELDS (type);
+  for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
{
@@ -30235,6 +30220,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 /* Aggregate initialization doesn't apply to an initializer expression.  */
 return NULL_TREE;
 
+  /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
   if (parms)
 {
   tree last = parms;
@@ -30426,7 +30427,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl

[gcc r15-434] c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:6d31a370e26eeb950c326332633b3e8e84b6630b

commit r15-434-g6d31a370e26eeb950c326332633b3e8e84b6630b
Author: Patrick Palka 
Date:   Mon May 13 09:53:40 2024 -0400

c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

During maybe_aggr_guide with a nested class template and paren init,
like with list init we need to consider the generic template type rather
than the partially instantiated type since partial instantiations don't
have (partially instantiated) TYPE_FIELDS.  In turn we need to partially
substitute PARMs in the paren init case as well.  As a drive-by improvement
it seems better to use outer_template_args instead of DECL_TI_ARGS during
this partial substitution so that we lower instead of substitute the
innermost template parameters, which is generally more robust.

And during alias_ctad_tweaks with a nested class template, even though
the guides may be already partially instantiated we still need to
substitute the outermost arguments into its constraints.

PR c++/114974
PR c++/114901
PR c++/114903

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
the paren init case.  Hoist out partial substitution logic
to apply to the paren init case as well.
(alias_ctad_tweaks): Substitute outer template arguments into
a guide's constraints.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr14.C: New test.
* g++.dg/cpp2a/class-deduction-alias20.C: New test.
* g++.dg/cpp2a/class-deduction-alias21.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc   | 39 --
 .../g++.dg/cpp2a/class-deduction-aggr14.C  | 11 ++
 .../g++.dg/cpp2a/class-deduction-alias20.C | 22 
 .../g++.dg/cpp2a/class-deduction-alias21.C | 38 +
 4 files changed, 93 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a7d9fcf930e2..4b71e199d27f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30194,26 +30194,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   if (init == error_mark_node)
return NULL_TREE;
   parms = collect_ctor_idx_types (init, parms);
-  /* If we're creating a deduction guide for a member class template,
-we've used the original template pattern type for the reshape_init
-above; this is done because we want PARMS to be a template parameter
-type, something that can be deduced when used as a function template
-parameter.  At this point the outer class template has already been
-partially instantiated (we deferred the deduction until the enclosing
-scope is non-dependent).  Therefore we have to partially instantiate
-PARMS, so that its template level is properly reduced and we don't get
-mismatches when deducing types using the guide with PARMS.  */
-  if (member_template_p)
-   {
- ++processing_template_decl;
- parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
- --processing_template_decl;
-   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
-  for (tree field = TYPE_FIELDS (type);
+  for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
{
@@ -30228,6 +30213,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 /* Aggregate initialization doesn't apply to an initializer expression.  */
 return NULL_TREE;
 
+  /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
   if (parms)
 {
   tree last = parms;
@@ -30419,7 +30420,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+   {
+ if (tree outer_targs = outer_template_args (f

Re: [PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-11 Thread Patrick Palka
On Fri, 10 May 2024, Jason Merrill wrote:

> On 5/9/24 16:23, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/14?  For trunk as a follow-up I can implement the
> > mentionted representation change to use CALL_EXPR instead of
> > MODOP_EXPR for a non-dependent simple assignment expression that
> > resolved to an operator= overload.
> > 
> > -- >8 --
> > 
> > r14-4111 made us check non-dependent assignment expressions ahead of
> > time, as well as give them a type.  Unlike for compound assignment
> > expressions however, if a simple assignment resolves to an operator
> > overload we still represent it as a (typed) MODOP_EXPR instead of a
> > CALL_EXPR to the selected overload.  This, I reckoned, was just a
> > pessimization (since we'll have to repeat overload resolution at
> > instantiatiation time) but should be harmless.  (And it should be
> > easily fixable by giving cp_build_modify_expr an 'overload' parameter).
> > 
> > But it breaks the below testcase ultimately because MODOP_EXPR (of
> > non-reference type) is always treated as an lvalue according to
> > lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42.
> > 
> > We can fix this by representing such assignment expressions as CALL_EXPRs
> > matching what that of compound assignments, but that turns out to
> > require some tweaking of our -Wparentheses warning logic which seems
> > unsuitable for backporting.
> > 
> > So this patch instead more conservatively fixes this by refining
> > lvalue_kind to consider the type of a (simple) MODOP_EXPR as we
> > already do for COND_EXPR.
> > 
> > PR c++/114994
> > 
> > gcc/cp/ChangeLog:
> > 
> > * tree.cc (lvalue_kind) : Consider the
> > type of a simple assignment expression.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/non-dependent32.C: New test.
> > ---
> >   gcc/cp/tree.cc |  7 +++
> >   .../g++.dg/template/non-dependent32.C  | 18 ++
> >   2 files changed, 25 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C
> > 
> > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> > index f1a23ffe817..0b97b789aab 100644
> > --- a/gcc/cp/tree.cc
> > +++ b/gcc/cp/tree.cc
> > @@ -275,6 +275,13 @@ lvalue_kind (const_tree ref)
> > /* We expect to see unlowered MODOP_EXPRs only during
> >  template processing.  */
> > gcc_assert (processing_template_decl);
> > +  if (TREE_CODE (TREE_OPERAND (ref, 1)) == NOP_EXPR
> > + && CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
> > +   /* As in the COND_EXPR case, but for non-dependent assignment
> > +  expressions created by build_x_modify_expr.  */
> > +   goto default_;
> 
> This seems overly specific, I'd think the same thing would apply to += and
> such?

We shouldn't see += etc of class type here since we already represent
those as CALL_EXPR to the selected operator=, but indeed it could
otherwise apply to +=.  Like so?

-- >8 -- 

Subject: [PATCH] c++: lvalueness of non-dependent assignment expr [PR114994]

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : Consider the
type of a class assignment expression.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.
---
 gcc/cp/tree.cc |  5 -
 .../g++.dg/template/non-dependent32.C  | 18 ++
 2 files changed, 22 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe817..9d37d255d8d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,7 +275,10 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
-  return clk_ordinary;
+  if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   goto default_;
+  else
+   return clk_ordinary;
 
 case MODIFY_EXPR:
 case TYPEID_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index 000..54252c7dfaf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int mai

Re: [PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-10 Thread Patrick Palka
On Thu, 9 May 2024, Patrick Palka wrote:

> On Thu, 9 May 2024, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/14?  For trunk as a follow-up I can implement the
> > mentionted representation change to use CALL_EXPR instead of
> > MODOP_EXPR for a non-dependent simple assignment expression that
> > resolved to an operator= overload.
> 
> FWIW, this is the WIP patch for that including the -Wparentheses
> logic adjustments needed to avoid regressing
> g++.dg/warn/Wparentheses-{32,33}.C

This patch survives bootstrap+regtest FWIW.  I'm not sure which approach
we should go with for backporting.

> 
>   PR c++/114994
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (build_new_op): Pass 'overload' to
>   cp_build_modify_expr.
>   * cp-tree.h (cp_build_modify_expr): New overload that
>   takes a tree* out-parameter.
>   * pt.cc (tsubst_expr) : Propagate
>   OPT_Wparentheses warning suppression to the result.
>   * semantics.cc (is_assignment_op_expr_p): Also recognize
>   templated operator expressions represented as a CALL_EXPR
>   to operator=.
>   * typeck.cc (cp_build_modify_expr): Add 'overload'
>   out-parameter and pass it to build_new_op.
>   (build_x_modify_expr): Pass 'overload' to cp_build_modify_expr.
> ---
>  gcc/cp/call.cc |  2 +-
>  gcc/cp/cp-tree.h   |  3 +++
>  gcc/cp/pt.cc   |  2 ++
>  gcc/cp/semantics.cc| 11 +++
>  gcc/cp/typeck.cc   | 18 ++
>  5 files changed, 31 insertions(+), 5 deletions(-)
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 7c4ecf08c4b..1cd4992330c 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
> code, int flags,
>switch (code)
>  {
>  case MODIFY_EXPR:
> -  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
> +  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, 
> complain);
>  
>  case INDIRECT_REF:
>return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index f82446331b3..505c04c6e52 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -8264,6 +8264,9 @@ extern tree cp_build_c_cast 
> (location_t, tree, tree,
>  extern cp_expr build_x_modify_expr   (location_t, tree,
>enum tree_code, tree,
>tree, tsubst_flags_t);
> +extern tree cp_build_modify_expr (location_t, tree,
> +  enum tree_code, tree,
> +  tree *, tsubst_flags_t);
>  extern tree cp_build_modify_expr (location_t, tree,
>enum tree_code, tree,
>tsubst_flags_t);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index f3d52acaaac..bc71e534cf8 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -21091,6 +21091,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
> complain, tree in_decl)
>   if (warning_suppressed_p (t, OPT_Wpessimizing_move))
> /* This also suppresses -Wredundant-move.  */
> suppress_warning (ret, OPT_Wpessimizing_move);
> + if (warning_suppressed_p (t, OPT_Wparentheses))
> +   suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
> }
>  
>   RETURN (ret);
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index b8c2bf8771f..e81f2b50d80 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -863,6 +863,17 @@ is_assignment_op_expr_p (tree t)
>  return false;
>  
>tree fndecl = cp_get_callee_fndecl_nofold (call);
> +  if (!fndecl
> +  && processing_template_decl
> +  && TREE_CODE (CALL_EXPR_FN (call)) == COMPONENT_REF)
> +{
> +  /* Also recognize (non-dependent) templated operator expressions that
> +  are represented as a direct call to operator=.
> +  TODO: maybe move this handling to cp_get_fndecl_from_callee for
> +  benefit of other callers.  */
> +  if (tree fns = maybe_get_fns (TREE_OPERAND (CALL_EXPR_FN (call), 1)))
> + fndecl = OVL_FIRST (fns);
> +}
>return fndecl != NULL_TREE
>  && DECL_ASSIGNMENT_OPERATOR_P (fndecl)
>  && DECL_OVERLOADED_OPERATOR_IS (fndecl, NOP_EXPR

Re: [PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-09 Thread Patrick Palka
On Thu, 9 May 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk/14?  For trunk as a follow-up I can implement the
> mentionted representation change to use CALL_EXPR instead of
> MODOP_EXPR for a non-dependent simple assignment expression that
> resolved to an operator= overload.

FWIW, this is the WIP patch for that including the -Wparentheses
logic adjustments needed to avoid regressing
g++.dg/warn/Wparentheses-{32,33}.C

PR c++/114994

gcc/cp/ChangeLog:

* call.cc (build_new_op): Pass 'overload' to
cp_build_modify_expr.
* cp-tree.h (cp_build_modify_expr): New overload that
takes a tree* out-parameter.
* pt.cc (tsubst_expr) : Propagate
OPT_Wparentheses warning suppression to the result.
* semantics.cc (is_assignment_op_expr_p): Also recognize
templated operator expressions represented as a CALL_EXPR
to operator=.
* typeck.cc (cp_build_modify_expr): Add 'overload'
out-parameter and pass it to build_new_op.
(build_x_modify_expr): Pass 'overload' to cp_build_modify_expr.
---
 gcc/cp/call.cc |  2 +-
 gcc/cp/cp-tree.h   |  3 +++
 gcc/cp/pt.cc   |  2 ++
 gcc/cp/semantics.cc| 11 +++
 gcc/cp/typeck.cc   | 18 ++
 5 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 7c4ecf08c4b..1cd4992330c 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
code, int flags,
   switch (code)
 {
 case MODIFY_EXPR:
-  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
+  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, complain);
 
 case INDIRECT_REF:
   return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f82446331b3..505c04c6e52 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8264,6 +8264,9 @@ extern tree cp_build_c_cast   
(location_t, tree, tree,
 extern cp_expr build_x_modify_expr (location_t, tree,
 enum tree_code, tree,
 tree, tsubst_flags_t);
+extern tree cp_build_modify_expr   (location_t, tree,
+enum tree_code, tree,
+tree *, tsubst_flags_t);
 extern tree cp_build_modify_expr   (location_t, tree,
 enum tree_code, tree,
 tsubst_flags_t);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f3d52acaaac..bc71e534cf8 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21091,6 +21091,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
  /* This also suppresses -Wredundant-move.  */
  suppress_warning (ret, OPT_Wpessimizing_move);
+   if (warning_suppressed_p (t, OPT_Wparentheses))
+ suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
  }
 
RETURN (ret);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b8c2bf8771f..e81f2b50d80 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -863,6 +863,17 @@ is_assignment_op_expr_p (tree t)
 return false;
 
   tree fndecl = cp_get_callee_fndecl_nofold (call);
+  if (!fndecl
+  && processing_template_decl
+  && TREE_CODE (CALL_EXPR_FN (call)) == COMPONENT_REF)
+{
+  /* Also recognize (non-dependent) templated operator expressions that
+are represented as a direct call to operator=.
+TODO: maybe move this handling to cp_get_fndecl_from_callee for
+benefit of other callers.  */
+  if (tree fns = maybe_get_fns (TREE_OPERAND (CALL_EXPR_FN (call), 1)))
+   fndecl = OVL_FIRST (fns);
+}
   return fndecl != NULL_TREE
 && DECL_ASSIGNMENT_OPERATOR_P (fndecl)
 && DECL_OVERLOADED_OPERATOR_IS (fndecl, NOP_EXPR);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5f16994300f..75b696e32e0 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9421,7 +9421,7 @@ build_modify_expr (location_t location,
 
 tree
 cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
- tree rhs, tsubst_flags_t complain)
+ tree rhs, tree *overload, tsubst_flags_t complain)
 {
   lhs = mark_lvalue_use_nonread (lhs);
 
@@ -9533,7 +9533,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum 
tree_code modifycode,
  rhs = unshare_expr (rhs);
tree op2 = TR

[PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-09 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/14?  For trunk as a follow-up I can implement the
mentionted representation change to use CALL_EXPR instead of
MODOP_EXPR for a non-dependent simple assignment expression that
resolved to an operator= overload.

-- >8 --

r14-4111 made us check non-dependent assignment expressions ahead of
time, as well as give them a type.  Unlike for compound assignment
expressions however, if a simple assignment resolves to an operator
overload we still represent it as a (typed) MODOP_EXPR instead of a
CALL_EXPR to the selected overload.  This, I reckoned, was just a
pessimization (since we'll have to repeat overload resolution at
instantiatiation time) but should be harmless.  (And it should be
easily fixable by giving cp_build_modify_expr an 'overload' parameter).

But it breaks the below testcase ultimately because MODOP_EXPR (of
non-reference type) is always treated as an lvalue according to
lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42.

We can fix this by representing such assignment expressions as CALL_EXPRs
matching what that of compound assignments, but that turns out to
require some tweaking of our -Wparentheses warning logic which seems
unsuitable for backporting.

So this patch instead more conservatively fixes this by refining
lvalue_kind to consider the type of a (simple) MODOP_EXPR as we
already do for COND_EXPR.

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : Consider the
type of a simple assignment expression.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.
---
 gcc/cp/tree.cc |  7 +++
 .../g++.dg/template/non-dependent32.C  | 18 ++
 2 files changed, 25 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe817..0b97b789aab 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,6 +275,13 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
+  if (TREE_CODE (TREE_OPERAND (ref, 1)) == NOP_EXPR
+ && CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   /* As in the COND_EXPR case, but for non-dependent assignment
+  expressions created by build_x_modify_expr.  */
+   goto default_;
+  /* A non-dependent (simple or compound) assignment expression that
+resolved to a built-in assignment function.  */
   return clk_ordinary;
 
 case MODIFY_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index 000..54252c7dfaf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int main() {
+  g();
+}
-- 
2.45.0.119.g0f3415f1f8



Re: [PATCH] c++: nested aggregate/alias CTAD fixes

2024-05-08 Thread Patrick Palka
On Wed, 8 May 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look
> OK for trunk and perhaps 14?
> 
> -- >8 --
> 
> During maybe_aggr_guide with a nested class template and paren init,
> like with list init we need to consider the generic template type rather
> than the partially instantiated type since only the former has
> TYPE_FIELDS.  And in turn we need to partially substitute PARMs in the
> paren init case as well.  As a drive-by improvement it seems better to
> use outer_template_args instead of DECL_TI_ARGS during this partial
> substitution so that we lower instead of substitute the innermost
> generic template arguments, which is generally more robust.

... lower instead of substitute the innermost _template parameters_, rather

> 
> And during alias_ctad_tweaks with a nested class template, even though
> the guides may be already partially instantiated we still need to
> use the full set of arguments, not just the innermost, when substituting
> its constraints.
> 
>   PR c++/114974
>   PR c++/114901
>   PR c++/114903
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
>   the paren init case.  Hoist out partial substitution logic
>   to apply to the paren init case as well.
>   (alias_ctad_tweaks): Substitute constraints using the full
>   set of template arguments.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/class-deduction-aggr14.C: New test.
>   * g++.dg/cpp2a/class-deduction-alias20.C: New test.
>   * g++.dg/cpp2a/class-deduction-alias21.C: New test.
> ---
>  gcc/cp/pt.cc  | 39 +++
>  .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++
>  .../g++.dg/cpp2a/class-deduction-alias20.C| 22 +++
>  .../g++.dg/cpp2a/class-deduction-alias21.C| 38 ++
>  4 files changed, 93 insertions(+), 17 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1816bfd1f40..f3d52acaaac 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -30192,26 +30192,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
> vec *args)
>if (init == error_mark_node)
>   return NULL_TREE;
>parms = collect_ctor_idx_types (init, parms);
> -  /* If we're creating a deduction guide for a member class template,
> -  we've used the original template pattern type for the reshape_init
> -  above; this is done because we want PARMS to be a template parameter
> -  type, something that can be deduced when used as a function template
> -  parameter.  At this point the outer class template has already been
> -  partially instantiated (we deferred the deduction until the enclosing
> -  scope is non-dependent).  Therefore we have to partially instantiate
> -  PARMS, so that its template level is properly reduced and we don't get
> -  mismatches when deducing types using the guide with PARMS.  */
> -  if (member_template_p)
> - {
> -   ++processing_template_decl;
> -   parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
> -   --processing_template_decl;
> - }
>  }
>else if (TREE_CODE (init) == TREE_LIST)
>  {
>int len = list_length (init);
> -  for (tree field = TYPE_FIELDS (type);
> +  for (tree field = TYPE_FIELDS (template_type);
>  len;
>  --len, field = DECL_CHAIN (field))
>   {
> @@ -30226,6 +30211,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
> vec *args)
>  /* Aggregate initialization doesn't apply to an initializer expression.  
> */
>  return NULL_TREE;
>  
> +  /* If we're creating a deduction guide for a member class template,
> + we've used the original template pattern type for the reshape_init
> + above; this is done because we want PARMS to be a template parameter
> + type, something that can be deduced when used as a function template
> + parameter.  At this point the outer class template has already been
> + partially instantiated (we deferred the deduction until the enclosing
> + scope is non-dependent).  Therefore we have to partially instantiate
> + PARMS, so that its template level is properly reduced and we don't get
> + mismatches when deducing types using the guide with PARMS.  */
> +  if (member_template_p)
> +{
> +  ++processing_template_decl;
> +  parms = tsubst (parms, outer_template_args (tmpl), complai

[PATCH] c++: nested aggregate/alias CTAD fixes

2024-05-08 Thread Patrick Palka
Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look
OK for trunk and perhaps 14?

-- >8 --

During maybe_aggr_guide with a nested class template and paren init,
like with list init we need to consider the generic template type rather
than the partially instantiated type since only the former has
TYPE_FIELDS.  And in turn we need to partially substitute PARMs in the
paren init case as well.  As a drive-by improvement it seems better to
use outer_template_args instead of DECL_TI_ARGS during this partial
substitution so that we lower instead of substitute the innermost
generic template arguments, which is generally more robust.

And during alias_ctad_tweaks with a nested class template, even though
the guides may be already partially instantiated we still need to
use the full set of arguments, not just the innermost, when substituting
its constraints.

PR c++/114974
PR c++/114901
PR c++/114903

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
the paren init case.  Hoist out partial substitution logic
to apply to the paren init case as well.
(alias_ctad_tweaks): Substitute constraints using the full
set of template arguments.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr14.C: New test.
* g++.dg/cpp2a/class-deduction-alias20.C: New test.
* g++.dg/cpp2a/class-deduction-alias21.C: New test.
---
 gcc/cp/pt.cc  | 39 +++
 .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++
 .../g++.dg/cpp2a/class-deduction-alias20.C| 22 +++
 .../g++.dg/cpp2a/class-deduction-alias21.C| 38 ++
 4 files changed, 93 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1816bfd1f40..f3d52acaaac 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30192,26 +30192,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   if (init == error_mark_node)
return NULL_TREE;
   parms = collect_ctor_idx_types (init, parms);
-  /* If we're creating a deduction guide for a member class template,
-we've used the original template pattern type for the reshape_init
-above; this is done because we want PARMS to be a template parameter
-type, something that can be deduced when used as a function template
-parameter.  At this point the outer class template has already been
-partially instantiated (we deferred the deduction until the enclosing
-scope is non-dependent).  Therefore we have to partially instantiate
-PARMS, so that its template level is properly reduced and we don't get
-mismatches when deducing types using the guide with PARMS.  */
-  if (member_template_p)
-   {
- ++processing_template_decl;
- parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
- --processing_template_decl;
-   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
-  for (tree field = TYPE_FIELDS (type);
+  for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
{
@@ -30226,6 +30211,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 /* Aggregate initialization doesn't apply to an initializer expression.  */
 return NULL_TREE;
 
+  /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
   if (parms)
 {
   tree last = parms;
@@ -30417,7 +30418,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+   {
+ if (tree outer_targs = outer_template_args (f))
+   ci = tsubst_constraint_info (ci, outer_targs, complain, 
in_decl);
+ ci = tsubst_constraint_info 

[gcc r14-10176] c++/modules: imported spec befriending class tmpl [PR114889]

2024-05-07 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:390bd23fd9c98dc40856beef05364f5d1c7b9d04

commit r14-10176-g390bd23fd9c98dc40856beef05364f5d1c7b9d04
Author: Patrick Palka 
Date:   Mon Apr 29 21:27:59 2024 -0400

c++/modules: imported spec befriending class tmpl [PR114889]

When adding to CLASSTYPE_BEFRIENDING_CLASSES as part of installing an
imported class definition, we need to look through TEMPLATE_DECL like
make_friend_class does.

Otherwise in the below testcase we won't add _Hashtable to
CLASSTYPE_BEFRIENDING_CLASSES of _Map_base, which leads to a bogus
access check failure for _M_hash_code.

PR c++/114889

gcc/cp/ChangeLog:

* module.cc (trees_in::read_class_def): Look through
TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-8_a.H: New test.
* g++.dg/modules/friend-8_b.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 22b20ac6c6aead2d3f36c413a77dd0b80adfec39)

Diff:
---
 gcc/cp/module.cc  |  2 ++
 gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++
 gcc/testsuite/g++.dg/modules/friend-8_b.C |  9 +
 3 files changed, 34 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c35e70b8cb8..3bf863e15d4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12498,6 +12498,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
 
  if (CLASS_TYPE_P (f))
{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}


Re: [PATCH v3] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-06 Thread Patrick Palka
On Mon, 6 May 2024, Jason Merrill wrote:

> On 5/3/24 07:17, Nathaniel Shead wrote:
> > On Thu, May 02, 2024 at 02:05:38PM -0400, Jason Merrill wrote:
> > > On 5/1/24 21:34, Nathaniel Shead wrote:
> > > > On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:
> > > > > On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:
> > > > > > 
> > > > > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > > > > > 
> > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk
> > > > > > > (and
> > > > > > > later 14.2)?  I don't think making it a GTY root is necessary but
> > > > > > > I felt
> > > > > > > perhaps better to be safe than sorry.
> > > > > > > 
> > > > > > > Potentially another approach would be to use DECL_UID instead like
> > > > > > > how
> > > > > > > entity_map does; would that be preferable?
> > > > > > > 
> > > > > > > -- >8 --
> > > > > > > 
> > > > > > > I got notified by Linaro CI and by checking testresults that there
> > > > > > > seems
> > > > > > > to be some occasional failures in tpl-friend-4_b.C on some
> > > > > > > architectures
> > > > > > > and standards modes since r15-59-gb5f6a56940e708.  I haven't been
> > > > > > > able
> > > > > > > to reproduce but looking at the backtrace I suspect the issue is
> > > > > > > that
> > > > > > > we're adding to the 'imported_temploid_friend' map a decl that is
> > > > > > > ultimately discarded, which then has its address reused by a later
> > > > > > > decl
> > > > > > > causing a failure in the assert in 'set_originating_module'.
> > > > > > > 
> > > > > > > This patch attempts to fix the issue in two ways: by ensuring that
> > > > > > > we
> > > > > > > only store the decl if we know it's a new decl (and hence won't be
> > > > > > > discarded), and by making the imported_temploid_friends map a GTY
> > > > > > > root
> > > > > > > so that even if the decl does get discarded later the address
> > > > > > > isn't
> > > > > > > reused.
> > > > > > > 
> > > > > > > gcc/cp/ChangeLog:
> > > > > > > 
> > > > > > >   * module.cc (imported_temploid_friends): Mark GTY, and...
> > > > > > >   (init_modules): ...allocate from GGC.
> > > > > > >   (trees_in::decl_value): Only write to
> > > > > > > imported_temploid_friends
> > > > > > >   for new decls.
> > > > > > > 
> > > > > > > Signed-off-by: Nathaniel Shead 
> > > > > > > ---
> > > > > > >gcc/cp/module.cc | 7 ---
> > > > > > >1 file changed, 4 insertions(+), 3 deletions(-)
> > > > > > > 
> > > > > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > > > > index 5b8ff5bc483..37d38bb9654 100644
> > > > > > > --- a/gcc/cp/module.cc
> > > > > > > +++ b/gcc/cp/module.cc
> > > > > > > @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
> > > > > > >   need to be attached to the same module as the temploid.
> > > > > > > This maps
> > > > > > >   these decls to the temploid they are instantiated them, as
> > > > > > > there is
> > > > > > >   no other easy way to get this information.  */
> > > > > > > -static hash_map *imported_temploid_friends;
> > > > > > > +static GTY(()) hash_map *imported_temploid_friends;
> > > > > > >
> > > > > > > //
> > > > > > >/* Tree streaming.   The tree streaming is very specific to the
> > > > > > > tree
> > > > > > > @@ -8327,7 +8327,8 @@ trees_in::decl_value ()
> > > > > > >  if (TREE_CODE (inner) == FUNCTION_DECL
> > > > > > >  || TREE_CODE (inner) == TYP

Re: [PATCH v2] Fix auto deduction for template specialization scopes [PR114915]

2024-05-06 Thread Patrick Palka
On Sat, 4 May 2024, Seyed Sajad Kahani wrote:

> The limitations of the initial patch (checking specializiation template 
> usage), have been discussed.
> 
> > I realized that for the case where we have a member function template
> > of a class template, and a specialization of the enclosing class only
> > (like below),
> >
> > template <>
> > template 
> > void S::f() {
> >   // some constrained auto
> > }
> >
> > When using S::f, DECL_TEMPLATE_INFO(fn) is non-zero, and
> > DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
> > DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
> > So it means that the patch will extract DECL_TI_ARGS(fn) as
> > outer_targs, and it would be   while the type of the
> > constrained auto will be as template  ... and will not be
> > dependent on the parameters of the enclosing class.
> > This means that again (outer_targs + targs) will have more depth than
> > auto_node levels.
> > This means that for the case where the function is not an explicit
> > specialization, but it is defined in an explicitly specialized scope,
> > the patch will not work.

Ah yes, good point!  This demonstrates that it doesn't suffice to
handle the TEMPLATE_TYPE_ORIG_LEVEL == 1 case contrary to what I
suggested earlier.

> 
> As described in more detail below, this patch attempts to resolve this issue 
> by trimming full_targs.
> 
> > > Another more context-unaware approach to fix this might be to only
> > > use the innermost level from 'full_targs' for satisfaction if
> > > TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> > > appeared in a context that doesn't have template parameters such as an
> > > explicit specialization or ordinary non-template function, and so
> > > only the level corresponding to the deduced type is needed for
> > > satisfaction.)
> > >
> > > Generalizing on that, another approach might be to handle missing_levels 
> > > < 0
> > > by removing -missing_levels from full_targs via 
> > > get_innermost_template_args.
> > > But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> > > case specifically.
> >
> > I was unable to understand why you think that it might not handle
> > TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
> > reasoning as follows.

Yes, sorry about that misleading suggestion.

> >
> > Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
> > For any case where missing_level < 0, it means that the type depends
> > on fewer levels than the template arguments used to materialize it.
> > This can only happen when the type is defined in an explicit
> > specialization scope. This explicit specialization might not occur in
> > its immediate scope.
> > Note that partial specialization (while changing the set of
> > parameters) cannot reduce the number of levels for the type.
> > Because of the fact that the enclosing scope of any explicit
> > specialization is explicitly specialized
> > (https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
> > on template parameters outside of its innermost explicit specialized
> > scope.
> > Assuming that there are no real missing levels, by removing those
> > levels, missing_level should be = 0. As a result, by roughly doing
> >
> > if (missing_levels < 0) {
> >   tree trimmed_full_args = get_innermost_template_args(full_targs,
> > TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
> >   full_targs = trimmed_full_args;
> > }
> > in pt.cc:31262, where we calculate and check missing_levels, we would
> > be able to fix the errors.
> > Note that, for the case where there are real missing levels, we are
> > putting irrelevant template arguments for the missing levels instead
> > of make_tree_vec(0). By this change:
> > - If the type is independent of those missing levels: it works fine either 
> > way.
> > - If the type is dependent on those missing levels: Instead of raising
> > an ICE, the compiler exhibits undefined behavior.

Makes sense.

> ---
>  gcc/cp/pt.cc  | 14 ++--
>  .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
>  .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
>  .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
>  4 files changed, 78 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..bdf03a1a7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree 
> init)
> OUTER_TARGS is used during template argument deduction (context == 
> adc_unify)
> to properly substitute the result.  It's also used in the adc_unify and
> adc_requirement contexts to communicate the necessary template arguments
> -   to satisfaction.  

Re: [PATCH] Fix auto deduction for template specialization scopes [114915].

2024-05-03 Thread Patrick Palka
Thanks for the patch!

On Wed, 1 May 2024, Seyed Sajad Kahani wrote:

> When deducing auto for `adc_return_type`, `adc_variable_type`, and 
> `adc_decomp_type` contexts (at the usage time), we try to resolve the 
> outermost template arguments to be used for satisfaction. This is done by one 
> of the following, depending on the scope:
> 
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and 
> extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other 
> conditions) for non-function scope variable declaration deductions 
> (decl.cc:8527).
> 
> Then, we do not retrieve the deeper layers of the template arguments; 
> instead, we fill the missing levels with dummy levels (pt.cc:31260).
> 
> The problem (that is shown in PR114915) is that we do not consider the case 
> where the deduction happens in a template specialization scope. In this case, 
> the type is not dependent on the outermost template arguments (which are the 
> specialization arguments). Yet, we still resolve the outermost template 
> arguments, and then the number of layers in the template arguments exceeds 
> the number of levels in the type. This causes the missing levels to be 
> negative. This leads to the rejection of valid code and ICEs (like segfault) 
> in the release mode. In the debug mode, it is possible to show as an 
> assertion failure (when creating a tree_vec with a negative size).
> The code that generates the issue is added to the test suite as 
> `g++.dg/cpp2a/concepts-placeholder14.C`.
> 
> This patch fixes the issue by checking that the template usage, whose 
> arguments are going to be used for satisfaction, is not a partial or explicit 
> specialization (and therefore it is an implicit or explicit instantiation). 
> This check is done in the two only places that affect the `outer_targs` for 
> the mentioned contexts.
> 
> One might ask why this is not implemented as a simple `missing_level > 0` 
> check. The reason is that the recovery from the negative `missing_levels` 
> will not be easy, and it is not clear how to recover from it. Therefore, it 
> is better to prevent it from happening.
> ---
>  gcc/cp/decl.cc|  1 +
>  gcc/cp/pt.cc  | 16 ++-
>  .../g++.dg/cpp2a/concepts-placeholder14.C | 20 +++
>  3 files changed, 32 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885..7e51f926e 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -8527,6 +8527,7 @@ cp_finish_decl (tree decl, tree init, bool 
> init_const_expr_p,
>if (PLACEHOLDER_TYPE_CONSTRAINTS_INFO (auto_node)
> && DECL_LANG_SPECIFIC (decl)
> && DECL_TEMPLATE_INFO (decl)
> +   && DECL_USE_TEMPLATE (decl) != 2

We should check !DECL_TEMPLATE_SPECIALIZATION instead of checking
DECL_USE_TEMPLATE directly.

And since DECL_TEMPLATE_SPECIALIZATION is true for both partial and
explicit specializations, I think we should check !in_template_context
as well in order to single out explicit specializations?

> && !DECL_FUNCTION_SCOPE_P (decl))
>   /* The outer template arguments might be needed for satisfaction.
>  (For function scope variables, do_auto_deduction will obtain the
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..fd646d873 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree 
> init)
> OUTER_TARGS is used during template argument deduction (context == 
> adc_unify)
> to properly substitute the result.  It's also used in the adc_unify and
> adc_requirement contexts to communicate the necessary template arguments
> -   to satisfaction.  OUTER_TARGS is ignored in other contexts.
> +   to satisfaction.  OUTER_TARGS will be used for other contexts if it is a
> +   function scope deduction. Otherwise it is ignored.
>  
> Additionally for adc_unify contexts TMPL is the template for which TYPE
> is a template parameter type.
> @@ -31235,8 +31236,11 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>   if (tree fn = current_function_decl)
> if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
>   {
> -   outer_targs = DECL_TEMPLATE_INFO (fn)
> - ? DECL_TI_ARGS (fn) : NULL_TREE;
> +   outer_targs = NULL_TREE; 
> +   if (DECL_TEMPLATE_INFO (fn) && DECL_USE_TEMPLATE (fn) != 2)
> +   {
> +   outer_targs = DECL_TI_ARGS (fn);
> +   }

Same here.

> if (LAMBDA_FUNCTION_P (fn))
>   {
> /* As in satisfy_declaration_constraints.  */
> @@ -31260,8 +31264,10 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>these missing levels, but this hack 

[PATCH] c++: replace tf_norm with a local flag

2024-05-03 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

-- >8 --

The tf_norm flag controlling whether to build diagnostic information
during constraint normalization doesn't need to be a global tsubst flag,
and is confusingly named.  This patch replaces it with a boolean flag
local to normalization.

gcc/cp/ChangeLog:

* constraint.cc (norm_info::norm_info): Take a boolean parameter
instead of tsubst_flags_t.
(norm_info::generate_diagnostics): Turn this predicate function
into a data member.
(normalize_logical_operation): Adjust after norm_info changes.
(normalize_concept_check): Likewise.
(normalize_atom): Likewise.
(get_normalized_constraints_from_info): Likewise.
(normalize_concept_definition): Likewise.
(normalize_constraint_expression): Likewise.
(normalize_placeholder_type_constraints): Likewise.
(satisfy_nondeclaration_constraints): Likewise.
* cp-tree.h (enum tsubst_flags): Remove tf_norm.
---
 gcc/cp/constraint.cc | 40 
 gcc/cp/cp-tree.h |  3 +--
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8a3b5d80ba7..3f0dab79bcd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -622,33 +622,29 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
 
 struct norm_info : subst_info
 {
-  explicit norm_info (tsubst_flags_t cmp)
-: norm_info (NULL_TREE, cmp)
+  explicit norm_info (bool diag)
+: norm_info (NULL_TREE, diag)
   {}
 
   /* Construct a top-level context for DECL.  */
 
-  norm_info (tree in_decl, tsubst_flags_t complain)
-: subst_info (tf_warning_or_error | complain, in_decl)
+  norm_info (tree in_decl, bool diag)
+: subst_info (tf_warning_or_error, in_decl),
+  generate_diagnostics (diag)
   {
 if (in_decl)
   {
initial_parms = DECL_TEMPLATE_PARMS (in_decl);
-   if (generate_diagnostics ())
+   if (generate_diagnostics)
  context = build_tree_list (NULL_TREE, in_decl);
   }
 else
   initial_parms = current_template_parms;
   }
 
-  bool generate_diagnostics() const
-  {
-return complain & tf_norm;
-  }
-
   void update_context(tree expr, tree args)
   {
-if (generate_diagnostics ())
+if (generate_diagnostics)
   {
tree map = build_parameter_mapping (expr, args, ctx_parms ());
context = tree_cons (map, expr, context);
@@ -679,6 +675,10 @@ struct norm_info : subst_info
  template parameters of ORIG_DECL.  */
 
   tree initial_parms = NULL_TREE;
+
+  /* Whether to build diagnostic information during normalization.  */
+
+  bool generate_diagnostics;
 };
 
 static tree normalize_expression (tree, tree, norm_info);
@@ -693,7 +693,7 @@ normalize_logical_operation (tree t, tree args, tree_code 
c, norm_info info)
   tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
 
   /* Build a new info object for the constraint.  */
-  tree ci = info.generate_diagnostics()
+  tree ci = info.generate_diagnostics
 ? build_tree_list (t, info.context)
 : NULL_TREE;
 
@@ -777,7 +777,7 @@ normalize_concept_check (tree check, tree args, norm_info 
info)
   if (!norm_cache)
 norm_cache = hash_table::create_ggc (31);
   norm_entry *entry = nullptr;
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the normal form of the substituted concept-id (when not
 diagnosing).  */
@@ -831,7 +831,7 @@ normalize_atom (tree t, tree args, norm_info info)
   if (info.in_decl && concept_definition_p (info.in_decl))
 ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
 
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
 later can cheaply compare two atoms using just pointer equality.  */
@@ -910,7 +910,7 @@ get_normalized_constraints_from_info (tree ci, tree 
in_decl, bool diag = false)
 
   /* Substitution errors during normalization are fatal.  */
   ++processing_template_decl;
-  norm_info info (in_decl, diag ? tf_norm : tf_none);
+  norm_info info (in_decl, diag);
   tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci), info);
   --processing_template_decl;
 
@@ -1012,7 +1012,7 @@ normalize_concept_definition (tree tmpl, bool diag)
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
   ++processing_template_decl;
-  norm_info info (tmpl, diag ? tf_norm : tf_none);
+  norm_info info (tmpl, diag);
   tree norm = get_normalized_constraints (def, info);
   --processing_template_decl;
 
@@ -1035,7 +1035,7 @@ normalize_constraint_expression (tree expr, norm_info 
info)
   if (!expr || expr == error_mark_node)
 return expr;
 
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 if (tree *p = 

Re: [PATCH] c++: 'typename T::X' vs 'struct T::X' lookup [PR109420]

2024-05-03 Thread Patrick Palka
Hey Andrew,

On Wed, 5 Apr 2023, Andrew Pinski wrote:

> On Wed, Apr 5, 2023 at 10:32 AM Patrick Palka via Gcc-patches
>  wrote:
> >
> > On Wed, 5 Apr 2023, Patrick Palka wrote:
> >
> > > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore
> > > non-types during the lookup, unless the TYPENAME_TYPE in question was
> > > followed by the :: scope resolution operator.  But there is another
> > > exception to this rule: we need to ignore non-types during the lookup
> > > also if the TYPENAME_TYPE was named with a tag other than 'typename',
> > > such as 'struct' or 'enum', as per [dcl.type.elab]/5.
> > >
> > > This patch implements this additional exception.  It occurred to me that
> > > the tf_qualifying_scope flag is probably unnecessary if we'd use the
> > > scope_type tag more thoroughly, but that requires parser changes that
> > > are probably too risky at this stage.  (I'm working on addressing the
> > > FIXME/TODOs here for GCC 14.)
> > >
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk?
> > >
> > >   PR c++/109420
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >   * decl.cc (make_typename_type): Also ignore non-types during
> > >   the lookup if tag_type is something other than none_type or
> > >   typename_type.
> > >   * pt.cc (tsubst) : Pass class_type or
> > >   enum_type as tag_type to make_typename_type as appropriate
> > >   instead of always passing typename_type.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >   * g++.dg/template/typename27.C: New test.
> > > ---
> > >  gcc/cp/decl.cc |  9 -
> > >  gcc/cp/pt.cc   |  9 -
> > >  gcc/testsuite/g++.dg/template/typename27.C | 19 +++
> > >  3 files changed, 35 insertions(+), 2 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/template/typename27.C
> > >
> > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > > index 5369714f9b3..a0a20c5accc 100644
> > > --- a/gcc/cp/decl.cc
> > > +++ b/gcc/cp/decl.cc
> > > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum 
> > > tag_types tag_type,
> > >   lookup will stop when we hit a dependent base.  */
> > >if (!dependent_scope_p (context))
> > >  {
> > > -  bool want_type = (complain & tf_qualifying_scope);
> > > +  /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore 
> > > non-types if
> > > +  the tag corresponds to a class-key or 'enum' (or is scope_type), 
> > > or if
> > > +  this typename is followed by :: as per 
> > > [basic.lookup.qual.general]/1.
> > > +  TODO: If we'd set the scope_type tag accurately on all 
> > > TYPENAME_TYPEs
> > > +  that are followed by :: then we wouldn't need the 
> > > tf_qualifying_scope
> > > +  flag.  */
> > > +  bool want_type = (tag_type != none_type && tag_type != 
> > > typename_type)
> > > + || (complain & tf_qualifying_scope);
> >
> > Here's v2 which just slightly improves this comment.  I reckon 
> > [basic.lookup.elab]
> > is a better reference than [dcl.type.elab]/5 for justifying why the
> > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs.
> >
> > -- >8 --
> >
> > PR c++/109420
> >
> > gcc/cp/ChangeLog:
> >
> > * decl.cc (make_typename_type): Also ignore non-types during the
> > lookup if tag_type corresponds to an elaborated-type-specifier.
> > * pt.cc (tsubst) : Pass class_type or
> > enum_type as tag_type to make_typename_type as appropriate
> > instead of always passing typename_type.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/template/typename27.C: New test.
> > ---
> >  gcc/cp/decl.cc | 12 +++-
> >  gcc/cp/pt.cc   |  9 -
> >  gcc/testsuite/g++.dg/template/typename27.C | 19 +++
> >  3 files changed, 38 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/template/typename27.C
> >
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index 5369714f9b3..772c059dc2c 100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -4

[gcc r15-123] c++: remove lookup_template_class's entering_scope flag

2024-05-02 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:f04dc89a991ddc6c08ac92c8ad29c6915c4ecafa

commit r15-123-gf04dc89a991ddc6c08ac92c8ad29c6915c4ecafa
Author: Patrick Palka 
Date:   Thu May 2 21:14:30 2024 -0400

c++: remove lookup_template_class's entering_scope flag

lookup_template_class's entering_scope flag controls whether to prefer
returning the primary template type A instead of the corresponding
implicit instantiation A.  When we want to set this flag as part of
substitution, we need to use tsubst_aggr_type which also takes this flag
as a parameter.  But having this separate entry point to type substitution
turned out to be subtly problematic because it doesn't reuse typedefs
like tsubst does, which r13-4729-gbe124477b38a71 fixed in a way that
respects the flag after the fact, by adjusting the entering_scope=false
result of lookup_template_class as if entering_scope=true was passed.

But if that's possible then it means lookup_template_class's
entering_scope flag is not necessary after all -- we can just do the
after-the-fact adjustment everywhere that we currently pass
entering_scope=true to it and tsubst_aggr_type.

To that end, this patch replaces this flag with an adjustment function
adjust_type_for_entering_scope, to be used whereever we currently need
the entering_scope=true behavior.  In turn we can get rid of
tsubst_aggr_type since the only reason we needed this entry point
was to be able to pass entering_scope=true to lookup_template_class.

gcc/cp/ChangeLog:

* coroutines.cc (instantiate_coro_traits): Adjust call to
lookup_template_class.
(instantiate_coro_handle_for_promise_type): Likewise.
* cp-tree.h (adjust_type_for_entering_scope): Declare.
(lookup_template_class): Adjust declaration.
* decl.cc (make_typename_type): Adjust call to
lookup_template_class. Likewise.
(get_tuple_size): Likewise.
(get_tuple_element_type): Likewise.
* pt.cc (adjust_type_for_entering_scope): Define.
(tsubst_entering_scope): Define.
(lookup_template_class): Remove entering_scope parameter.
Replace tsubst_aggr_type call with tsubst_entering_scope.
(tsubst_aggr_type): Remove.
(tsubst_aggr_type_1): Inline into tsubst.
(tsubst_function_decl): Replace tsubst_aggr_type call
with tsubst_entering_scope.
(tsubst_template_decl): Likewise.
(tsubst_decl): Likewise.
(tsubst) :
Inlined from tsubst_aggr_type_1.
: Adjust calls to
lookup_template_class.
: Replace tsubst_aggr_type call with
tsubst_entering_scope.
: Likewise.
Increment processing_template_decl when substituting the
context.
(tsubst_expr) : Replace tsubst_aggr_type
call with tsubst_entering_scope.
: Likewise.
(instantiate_template): Likewise.
(resolve_typename_type): Adjust lookup_template_class call
and call adjust_type_for_entering_scope afterward.
(listify): Adjust lookup_template_class call.
(alias_ctad_tweaks): Likewise.
* semantics.cc (finish_template_type): Adjust lookup_template_class
call and maybe call adjust_type_for_entering_scope afterward.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/coroutines.cc |   4 +-
 gcc/cp/cp-tree.h |   3 +-
 gcc/cp/decl.cc   |   4 +-
 gcc/cp/pt.cc | 207 ---
 gcc/cp/semantics.cc  |   4 +-
 5 files changed, 88 insertions(+), 134 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index b05cb9eb330..97bc211ff67 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -353,7 +353,7 @@ instantiate_coro_traits (tree fndecl, location_t kw)
   tree traits_class
 = lookup_template_class (coro_traits_templ, targ,
 /*in_decl=*/NULL_TREE, /*context=*/NULL_TREE,
-/*entering scope=*/false, tf_warning_or_error);
+tf_warning_or_error);
 
   if (traits_class == error_mark_node)
 {
@@ -400,7 +400,7 @@ instantiate_coro_handle_for_promise_type (location_t kw, 
tree promise_type)
 = lookup_template_class (coro_handle_identifier, targ,
 /* in_decl=*/NULL_TREE,
 /* context=*/std_node,
-/* entering scope=*/false, tf_warning_or_error);
+tf_warning_or_error);
 
   if (handle_type == error_mark_node)
 {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 933504b4821..1ba7054f8bc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7524,8 +7524,9 @@ extern tree push_template_decl(tree, 
bool

Re: [PATCH 2/2] c++: remove lookup_template_class's entering_scope flag

2024-05-02 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 5/1/24 13:40, Patrick Palka wrote:
> > On Wed, 1 May 2024, Jason Merrill wrote:
> > 
> > > On 5/1/24 12:41, Patrick Palka wrote:
> > > > On Fri, 2 Feb 2024, Patrick Palka wrote:
> > > > 
> > > > > Bootstrapped and regtested on x86_64-pc-linux, does this look like
> > > > > an improvement?  This is not a bugfix and barely related to the
> > > > > previous
> > > > > patch, but the previous patch's new use of entering_scope=true
> > > > > motivated
> > > > > me to submit this patch since it seems like a nice simplification.
> > > > 
> > > > Ping, now that stage 1 is open.
> > > 
> > > Thanks for the ping.  The earlier message isn't showing up in Thunderbird
> > > for
> > > some reason, though I see it in the gmail web interface...
> > 
> > Ah, weird.  No worries, this patch was very much stage 1 material anyway.
> > 
> > > 
> > > > > @@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t
> > > > > complain, tree in_decl)
> > > > >   ctx = TREE_VEC_ELT (ctx, 0);
> > > > > }
> > > > >   else
> > > > > -   ctx = tsubst_aggr_type (ctx, args,
> > > > > -   complain | tf_qualifying_scope,
> > > > > -   in_decl, /*entering_scope=*/1);
> > > > > +   {
> > > > > + ctx = tsubst_scope (ctx, args, complain, in_decl);
> > > 
> > > Why is this one tsubst_scope while the others are all plain tsubst?
> > 
> > Ah, just because the call to tsubst_aggr_type being replace passes
> > tf_qualifying_scope already, so we might as well use tsubst_scope
> > as shorthand.
> > 
> > > Do we want a tsubst_entering_scope function?
> > 
> > Which is just shorthand for tsubst + adjust_type_for_entering_scope?
> 
> That's what I was thinking.
> 
> > Sure, though I was wondering if we eventually might want to get rid of
> > the distinction between the primary template type A and the generic
> > instantiation A, and we could treat this as an incremental step
> > towards that (then we'd just eventually remove the
> > adjust_type_for_entering_scope calls and keep the tsubst calls).
> 
> I don't think we want that; having the distinction helps to avoid wrongly
> looking up members of the primary template in contexts that shouldn't be able
> to.

Makes sense.  How does the following look?

The name tsubst_entering_scope sounds confusingly similar to
tsubst_scope, but I can't think of a better name for it or for
adjust_type_for_entering_scope :/

-- >8 --

Subject: [PATCH] c++: remove lookup_template_class's entering_scope flag
gcc/cp/ChangeLog:

* coroutines.cc (instantiate_coro_traits): Adjust call to
lookup_template_class.
(instantiate_coro_handle_for_promise_type): Likewise.
* cp-tree.h (adjust_type_for_entering_scope): Declare.
(lookup_template_class): Adjust declaration.
* decl.cc (make_typename_type): Adjust call to
lookup_template_class. Likewise.
(get_tuple_size): Likewise.
(get_tuple_element_type): Likewise.
* pt.cc (adjust_type_for_entering_scope): Define.
(tsubst_entering_scope): Define.
(lookup_template_class): Remove entering_scope parameter.
Replace tsubst_aggr_type call with tsubst_entering_scope.
(tsubst_aggr_type): Remove.
(tsubst_aggr_type_1): Inline into tsubst.
(tsubst_function_decl): Replace tsubst_aggr_type call
with tsubst_entering_scope.
(tsubst_template_decl): Likewise.
(tsubst_decl): Likewise.
(tsubst) :
Inlined from tsubst_aggr_type_1.
: Adjust calls to
lookup_template_class.
: Replace tsubst_aggr_type call with
tsubst_scope followed by adjust_type_for_entering_scope.
: Replace tsubst_aggr_type
call with tsubst_entering_scope.
Increment processing_template_decl when substituting the
context.
(tsubst_expr) : Replace tsubst_aggr_type
call with tsubst_entering_scope.
: Likewise.
(instantiate_template): Likewise.
(resolve_typename_type): Adjust lookup_template_class call
and call adjust_type_for_entering_scope afterward.
(listify): Adjust lookup_template_class call.
(alias_ctad_tweaks): Likewise.
* semantics.cc (finish_template_type): Adjust lookup_template_class
call and maybe call adjust_type_for_entering_scope afterward.
---
 gcc/cp/coroutines.cc |   4 +-
 gcc/cp/cp-tree.h

Re: [PATCH v14 21/26] c++: Implement __rank built-in trait

2024-05-02 Thread Patrick Palka
On Tue, 30 Apr 2024, Jason Merrill wrote:

> On 2/28/24 11:26, Ken Matsui wrote:
> > This patch implements built-in trait for std::rank.
> 
> __rank seems too short, maybe __array_rank?
> 
> Actually, it occurs to me that perhaps we should have been adding __builtin to
> all of these rather than just __ and the library trait name.  I guess it's too
> late to do that for the GCC 14 traits, but we could do it for this group?

Clang already implements many of these built-in, without using
"__builtin" in their name.  Shouldn't we be consistent with Clang where
we can?

> 
> > gcc/cp/ChangeLog:
> > 
> > * cp-trait.def: Define __rank.
> > * constraint.cc (diagnose_trait_expr): Handle CPTK_RANK.
> > * semantics.cc (trait_expr_value): Likewise.
> > (finish_trait_expr): Likewise.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/ext/has-builtin-1.C: Test existence of __rank.
> > * g++.dg/ext/rank.C: New test.
> > 
> > Signed-off-by: Ken Matsui 
> > ---
> >   gcc/cp/constraint.cc |  3 +++
> >   gcc/cp/cp-trait.def  |  1 +
> >   gcc/cp/semantics.cc  | 23 ---
> >   gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
> >   gcc/testsuite/g++.dg/ext/rank.C  | 24 
> >   5 files changed, 51 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/ext/rank.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 000df847342..23ea66d9c12 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3870,6 +3870,9 @@ diagnose_trait_expr (tree expr, tree args)
> >   case CPTK_IS_VOLATILE:
> > inform (loc, "  %qT is not a volatile type", t1);
> > break;
> > +case CPTK_RANK:
> > +  inform (loc, "  %qT cannot yield a rank", t1);
> > +  break;
> >   case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > inform (loc, "  %qT is not a reference that binds to a temporary "
> >   "object of type %qT (direct-initialization)", t1, t2);
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 2d1cb7c227c..85056c8140b 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -99,6 +99,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE,
> > "__is_trivially_copyable", 1)
> >   DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
> >   DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
> >   DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
> > +DEFTRAIT_EXPR (RANK, "__rank", 1)
> >   DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY,
> > "__reference_constructs_from_temporary", 2)
> >   DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY,
> > "__reference_converts_from_temporary", 2)
> >   DEFTRAIT_TYPE (REMOVE_ALL_EXTENTS, "__remove_all_extents", 1)
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 45dc509855a..7242db75248 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12550,6 +12550,9 @@ trait_expr_value (cp_trait_kind kind, tree type1,
> > tree type2)
> >   case CPTK_IS_DEDUCIBLE:
> > return type_targs_deducible_from (type1, type2);
> >   +/* __rank is handled in finish_trait_expr. */
> > +case CPTK_RANK:
> 
> This should have a gcc_unreachable.
> 
> > +
> >   #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> >   case CPTK_##CODE:
> >   #include "cp-trait.def"
> > @@ -12622,7 +12625,10 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> > if (processing_template_decl)
> >   {
> > tree trait_expr = make_node (TRAIT_EXPR);
> > -  TREE_TYPE (trait_expr) = boolean_type_node;
> > +  if (kind == CPTK_RANK)
> > +   TREE_TYPE (trait_expr) = size_type_node;
> > +  else
> > +   TREE_TYPE (trait_expr) = boolean_type_node;
> > TRAIT_EXPR_TYPE1 (trait_expr) = type1;
> > TRAIT_EXPR_TYPE2 (trait_expr) = type2;
> > TRAIT_EXPR_KIND (trait_expr) = kind;
> > @@ -12714,6 +12720,7 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> >   case CPTK_IS_UNBOUNDED_ARRAY:
> >   case CPTK_IS_UNION:
> >   case CPTK_IS_VOLATILE:
> > +case CPTK_RANK:
> > break;
> > case CPTK_IS_LAYOUT_COMPATIBLE:
> > @@ -12745,8 +12752,18 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> > gcc_unreachable ();
> >   }
> >   -  tree val = (trait_expr_value (kind, type1, type2)
> > - ? boolean_true_node : boolean_false_node);
> > +  tree val;
> > +  if (kind == CPTK_RANK)
> > +{
> > +  size_t rank = 0;
> > +  for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
> > +   ++rank;
> > +  val = build_int_cst (size_type_node, rank);
> > +}
> > +  else
> > +val = (trait_expr_value (kind, type1, type2)
> > +  ? boolean_true_node : boolean_false_node);
> > +
> > return maybe_wrap_with_location (val, loc);
> >   }
> >   diff --git 

Re: [PATCH v14 21/26] c++: Implement __rank built-in trait

2024-05-02 Thread Patrick Palka
On Tue, 30 Apr 2024, Jason Merrill wrote:

> On 2/28/24 11:26, Ken Matsui wrote:
> > This patch implements built-in trait for std::rank.
> 
> __rank seems too short, maybe __array_rank?
> 
> Actually, it occurs to me that perhaps we should have been adding __builtin to
> all of these rather than just __ and the library trait name.  I guess it's too
> late to do that for the GCC 14 traits, but we could do it for this group?

Clang already implements many of these built-in, without using
"__builtin" in their name.  Shouldn't we be consistent with Clang where
we can?

> 
> > gcc/cp/ChangeLog:
> > 
> > * cp-trait.def: Define __rank.
> > * constraint.cc (diagnose_trait_expr): Handle CPTK_RANK.
> > * semantics.cc (trait_expr_value): Likewise.
> > (finish_trait_expr): Likewise.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/ext/has-builtin-1.C: Test existence of __rank.
> > * g++.dg/ext/rank.C: New test.
> > 
> > Signed-off-by: Ken Matsui 
> > ---
> >   gcc/cp/constraint.cc |  3 +++
> >   gcc/cp/cp-trait.def  |  1 +
> >   gcc/cp/semantics.cc  | 23 ---
> >   gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
> >   gcc/testsuite/g++.dg/ext/rank.C  | 24 
> >   5 files changed, 51 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/ext/rank.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 000df847342..23ea66d9c12 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3870,6 +3870,9 @@ diagnose_trait_expr (tree expr, tree args)
> >   case CPTK_IS_VOLATILE:
> > inform (loc, "  %qT is not a volatile type", t1);
> > break;
> > +case CPTK_RANK:
> > +  inform (loc, "  %qT cannot yield a rank", t1);
> > +  break;
> >   case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > inform (loc, "  %qT is not a reference that binds to a temporary "
> >   "object of type %qT (direct-initialization)", t1, t2);
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 2d1cb7c227c..85056c8140b 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -99,6 +99,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE,
> > "__is_trivially_copyable", 1)
> >   DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
> >   DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
> >   DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
> > +DEFTRAIT_EXPR (RANK, "__rank", 1)
> >   DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY,
> > "__reference_constructs_from_temporary", 2)
> >   DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY,
> > "__reference_converts_from_temporary", 2)
> >   DEFTRAIT_TYPE (REMOVE_ALL_EXTENTS, "__remove_all_extents", 1)
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 45dc509855a..7242db75248 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12550,6 +12550,9 @@ trait_expr_value (cp_trait_kind kind, tree type1,
> > tree type2)
> >   case CPTK_IS_DEDUCIBLE:
> > return type_targs_deducible_from (type1, type2);
> >   +/* __rank is handled in finish_trait_expr. */
> > +case CPTK_RANK:
> 
> This should have a gcc_unreachable.
> 
> > +
> >   #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> >   case CPTK_##CODE:
> >   #include "cp-trait.def"
> > @@ -12622,7 +12625,10 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> > if (processing_template_decl)
> >   {
> > tree trait_expr = make_node (TRAIT_EXPR);
> > -  TREE_TYPE (trait_expr) = boolean_type_node;
> > +  if (kind == CPTK_RANK)
> > +   TREE_TYPE (trait_expr) = size_type_node;
> > +  else
> > +   TREE_TYPE (trait_expr) = boolean_type_node;
> > TRAIT_EXPR_TYPE1 (trait_expr) = type1;
> > TRAIT_EXPR_TYPE2 (trait_expr) = type2;
> > TRAIT_EXPR_KIND (trait_expr) = kind;
> > @@ -12714,6 +12720,7 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> >   case CPTK_IS_UNBOUNDED_ARRAY:
> >   case CPTK_IS_UNION:
> >   case CPTK_IS_VOLATILE:
> > +case CPTK_RANK:
> > break;
> > case CPTK_IS_LAYOUT_COMPATIBLE:
> > @@ -12745,8 +12752,18 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> > gcc_unreachable ();
> >   }
> >   -  tree val = (trait_expr_value (kind, type1, type2)
> > - ? boolean_true_node : boolean_false_node);
> > +  tree val;
> > +  if (kind == CPTK_RANK)
> > +{
> > +  size_t rank = 0;
> > +  for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
> > +   ++rank;
> > +  val = build_int_cst (size_type_node, rank);
> > +}
> > +  else
> > +val = (trait_expr_value (kind, type1, type2)
> > +  ? boolean_true_node : boolean_false_node);
> > +
> > return maybe_wrap_with_location (val, loc);
> >   }
> >   diff --git 

Re: [PATCH] c++/modules: Stream unmergeable temporaries by value again [PR114856]

2024-05-02 Thread Patrick Palka
On Thu, 2 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/14.2?
> 
> Another alternative would be to stream such !DECL_NAME temporaries with
> a merge key of MK_unique rather than attempting to find the matching
> (nonexistant) field of the class context.

Both approaches sound good to me, hard to say which one is preferable..

The handling of function-scope vs class-scope temporaries seems to start
diverging in:

@@ -8861,28 +8861,6 @@ trees_out::decl_node (tree decl, walk_kind ref)
   return false;
 }
 
!  tree ctx = CP_DECL_CONTEXT (decl);
!  depset *dep = NULL;
!  if (streaming_p ())
!dep = dep_hash->find_dependency (decl);
!  else if (TREE_CODE (ctx) != FUNCTION_DECL
!  || TREE_CODE (decl) == TEMPLATE_DECL
!  || DECL_IMPLICIT_TYPEDEF_P (decl)
!  || (DECL_LANG_SPECIFIC (decl)
!  && DECL_MODULE_IMPORT_P (decl)))
!{
!  auto kind = (TREE_CODE (decl) == NAMESPACE_DECL
!  && !DECL_NAMESPACE_ALIAS (decl)
!  ? depset::EK_NAMESPACE : depset::EK_DECL);
!  dep = dep_hash->add_dependency (decl, kind);
!}
!
!  if (!dep)
!{
!  /* Some internal entity of context.  Do by value.  */
!  decl_value (decl, NULL);
!  return false;
!}
 
   if (dep->get_entity_kind () == depset::EK_REDIRECT)
 {

where for a class-scope temporary we add a dependency for it, stream
it by reference, and then stream it by value separately, which seems
unnecessary.

So if we decide to keep the create_temporary_var change, we probably
would want to unify this code path's handling of temporaries (i.e.
don't add_dependency a temporary regardless of its context).

If we decide your partially revert the create_temporary_var change,
your patch LGTM.

> 
> -- >8 --
> 
> In r14-9266-g2823b4d96d9ec4 I gave all temporary vars a DECL_CONTEXT,
> including those at namespace or global scope, so that they could be
> properly merged across importers.  However, not all of these temporary
> vars are actually supposed to be mergeable.
> 
> For instance, in the attached testcase we have an unnamed temporary var
> used in the NSDMI of a class member, which cannot properly merged -- but
> it also doesn't need to be, as it'll be thrown away when the class type
> itself is merged anyway.
> 
> This patch reverts the change made above and instead makes a weaker
> adjustment that only causes temporary vars with linkage have a
> DECL_CONTEXT to merge from.  This way these unnamed, "unmergeable"
> temporaries are properly streamed by value again.
> 
>   PR c++/114856
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (make_temporary_var_for_ref_to_temp): Set context for
>   temporaries with linkage.
>   * init.cc (create_temporary_var): Revert to only set context
>   when in a function decl.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/pr114856.h: New test.
>   * g++.dg/modules/pr114856_a.H: New test.
>   * g++.dg/modules/pr114856_b.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/call.cc|  1 +
>  gcc/cp/init.cc|  2 +-
>  gcc/testsuite/g++.dg/modules/pr114856.h   | 12 
>  gcc/testsuite/g++.dg/modules/pr114856_a.H |  5 +
>  gcc/testsuite/g++.dg/modules/pr114856_b.C |  5 +
>  5 files changed, 24 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr114856.h
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr114856_a.H
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr114856_b.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index dbdd7c29fe8..3b8889ac301 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -13799,6 +13799,7 @@ make_temporary_var_for_ref_to_temp (tree decl, tree 
> type)
>  
>tree name = mangle_ref_init_variable (decl);
>DECL_NAME (var) = name;
> +  DECL_CONTEXT (var) = current_scope ();
>SET_DECL_ASSEMBLER_NAME (var, name);
>  }
>else
> diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> index a93ce00800c..e758a8c8568 100644
> --- a/gcc/cp/init.cc
> +++ b/gcc/cp/init.cc
> @@ -4287,7 +4287,7 @@ create_temporary_var (tree type)
>TREE_USED (decl) = 1;
>DECL_ARTIFICIAL (decl) = 1;
>DECL_IGNORED_P (decl) = 1;
> -  DECL_CONTEXT (decl) = current_scope ();
> +  DECL_CONTEXT (decl) = current_function_decl;
>  
>return decl;
>  }
> diff --git a/gcc/testsuite/g++.dg/modules/pr114856.h 
> b/gcc/testsuite/g++.dg/modules/pr114856.h
> new file mode 100644
> index 000..b1a3c2cd834
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr114856.h
> @@ -0,0 +1,12 @@
> +// PR c++/114856
> +
> +#include 
> +struct A {
> +  ~A();
> +};
> +struct V {
> +  V(std::initializer_list);
> +};
> +struct data {
> +  V v{{}};
> +};
> diff --git a/gcc/testsuite/g++.dg/modules/pr114856_a.H 
> b/gcc/testsuite/g++.dg/modules/pr114856_a.H
> new file mode 100644
> index 000..6195277dbde
> --- /dev/null

Re: [PATCH v2] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-02 Thread Patrick Palka
On Wed, May 1, 2024 at 9:35 PM Nathaniel Shead
 wrote:
>
> On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:
> > On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:
> > >
> > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > >
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk (and
> > > > later 14.2)?  I don't think making it a GTY root is necessary but I felt
> > > > perhaps better to be safe than sorry.
> > > >
> > > > Potentially another approach would be to use DECL_UID instead like how
> > > > entity_map does; would that be preferable?
> > > >
> > > > -- >8 --
> > > >
> > > > I got notified by Linaro CI and by checking testresults that there seems
> > > > to be some occasional failures in tpl-friend-4_b.C on some architectures
> > > > and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
> > > > to reproduce but looking at the backtrace I suspect the issue is that
> > > > we're adding to the 'imported_temploid_friend' map a decl that is
> > > > ultimately discarded, which then has its address reused by a later decl
> > > > causing a failure in the assert in 'set_originating_module'.
> > > >
> > > > This patch attempts to fix the issue in two ways: by ensuring that we
> > > > only store the decl if we know it's a new decl (and hence won't be
> > > > discarded), and by making the imported_temploid_friends map a GTY root
> > > > so that even if the decl does get discarded later the address isn't
> > > > reused.
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > >   * module.cc (imported_temploid_friends): Mark GTY, and...
> > > >   (init_modules): ...allocate from GGC.
> > > >   (trees_in::decl_value): Only write to imported_temploid_friends
> > > >   for new decls.
> > > >
> > > > Signed-off-by: Nathaniel Shead 
> > > > ---
> > > >  gcc/cp/module.cc | 7 ---
> > > >  1 file changed, 4 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > index 5b8ff5bc483..37d38bb9654 100644
> > > > --- a/gcc/cp/module.cc
> > > > +++ b/gcc/cp/module.cc
> > > > @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
> > > > need to be attached to the same module as the temploid.  This maps
> > > > these decls to the temploid they are instantiated them, as there is
> > > > no other easy way to get this information.  */
> > > > -static hash_map *imported_temploid_friends;
> > > > +static GTY(()) hash_map *imported_temploid_friends;
> > > >
> > > >  //
> > > >  /* Tree streaming.   The tree streaming is very specific to the tree
> > > > @@ -8327,7 +8327,8 @@ trees_in::decl_value ()
> > > >if (TREE_CODE (inner) == FUNCTION_DECL
> > > >|| TREE_CODE (inner) == TYPE_DECL)
> > > >  if (tree owner = tree_node ())
> > > > -  imported_temploid_friends->put (decl, owner);
> > > > +  if (is_new)
> > > > + imported_temploid_friends->put (decl, owner);
> > >
> > > Hmm, I'm not seeing this code path getting reached for tpl-friend-4_b.C.
> > > It seems we're instead adding to imported_temploid_friends from
> > > propagate_defining_module, during tsubst_friend_function.
> > >
> > > What seems to be happening is that we we first tsubst_friend_function
> > > 'foo' from TPL, and then we tsubst_friend_function 'foo' from 
> > > DEF,
> > > which ends up calling duplicate_decls, which ggc_frees this 'foo'
> > > redeclaration that is still present in the imported_temploid_friends map.
> > >
> > > So I don't think marking imported_temploid_friends as a GC root would
> > > help with this situation.  If we want to keep imported_temploid_friends
> > > as a tree -> tree map, I think we just need to ensure that a decl
> > > is removed from the map upon getting ggc_free'd from e.g.  
> > > duplicate_decls.
> > >
> > > But it seems simpler to use DECL_UID as the key instead, since those
> > > never get reused even after the decl gets ggc_free'd IIUC.
> > >
> >
> > Ah right, thanks for digging into that further.  Yup OK, I think
> > probably the 

Re: [PATCH] c++: problematic assert in reference_binding [PR113141]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Patrick Palka wrote:

> On Wed, 1 May 2024, Jason Merrill wrote:
> 
> > On 4/12/24 13:22, Patrick Palka wrote:
> > > On Fri, 12 Apr 2024, Jason Merrill wrote:
> > > 
> > > > On 3/26/24 09:44, Patrick Palka wrote:
> > > > > On Thu, 7 Mar 2024, Jason Merrill wrote:
> > > > > 
> > > > > > On 1/29/24 17:42, Patrick Palka wrote:
> > > > > > > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > > > > > > 
> > > > > > > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > > > > > > 
> > > > > > > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > > > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does
> > > > > > > > > > > > this
> > > > > > > > > > > > look
> > > > > > > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, 
> > > > > > > > > > > > but
> > > > > > > > > > > > at
> > > > > > > > > > > > least
> > > > > > > > > > > > it safely fixes these testcases I guess.  Note that
> > > > > > > > > > > > there's
> > > > > > > > > > > > implementation disagreement about the second testcase, 
> > > > > > > > > > > > GCC
> > > > > > > > > > > > always
> > > > > > > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > > > > > > 
> > > > > > > > > > > Because of trying to initialize int& from {c}; removing 
> > > > > > > > > > > the
> > > > > > > > > > > extra
> > > > > > > > > > > braces
> > > > > > > > > > > makes it work everywhore.
> > > > > > > > > > > 
> > > > > > > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we
> > > > > > > > > > > always
> > > > > > > > > > > generate a
> > > > > > > > > > > prvalue in this case, so perhaps we shouldn't recalculate 
> > > > > > > > > > > if
> > > > > > > > > > > the
> > > > > > > > > > > initializer is an init-list?
> > > > > > > > > > 
> > > > > > > > > > ...but it seems bad to silently bind a const int& to a 
> > > > > > > > > > prvalue
> > > > > > > > > > instead
> > > > > > > > > > of
> > > > > > > > > > directly to the reference returned by the operator, as clang
> > > > > > > > > > does
> > > > > > > > > > if
> > > > > > > > > > we add
> > > > > > > > > > const to the second testcase, so I think there's a defect in
> > > > > > > > > > the
> > > > > > > > > > standard
> > > > > > > > > > here.
> > > > > > > > > 
> > > > > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > > > > reference-related to E or scalar, ..."
> > > > > > > > > 
> > > > > > > > > > Maybe for now also disable the maybe_valid heuristics in the
> > > > > > > > > > case
> > > > > > > > > > of
> > > > > > > > > > an
> > > > > > > > > > init-list?
> > > > > > > > > > 
> > > > > > > > > > > The first testcase is special because it's a C-style cast;
> > > > > > > > > > > seems
> > > > > > > > > > > like the
> > > > > > > > > > > maybe_valid = false heuristics should be disabled if
> > >

[gcc r13-8670] c++: problematic assert in reference_binding [PR113141]

2024-05-01 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:c70abea054fe0021b7b2c2e07996afaadc17a07b

commit r13-8670-gc70abea054fe0021b7b2c2e07996afaadc17a07b
Author: Patrick Palka 
Date:   Wed May 1 18:16:08 2024 -0400

c++: problematic assert in reference_binding [PR113141]

r14-9946 / r14-9947 fixed this PR properly for GCC 14.

For GCC 13, let's just remove the problematic assert.

PR c++/113141

gcc/cp/ChangeLog:

* call.cc (reference_binding): Remove badness criteria sanity
check in the recursive case.

gcc/testsuite/ChangeLog:

* g++.dg/conversion/ref12.C: New test.
* g++.dg/cpp0x/initlist-ref1.C: new test.

Diff:
---
 gcc/cp/call.cc |  1 -
 gcc/testsuite/g++.dg/conversion/ref12.C| 13 +
 gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C | 16 
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index b10bdc62d38..70c7f6178b8 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2017,7 +2017,6 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
if (!new_second)
  return NULL;
conv = merge_conversion_sequences (t, new_second);
-   gcc_assert (maybe_valid_p || conv->bad_p);
return conv;
  }
 }
diff --git a/gcc/testsuite/g++.dg/conversion/ref12.C 
b/gcc/testsuite/g++.dg/conversion/ref12.C
new file mode 100644
index 000..633b7e48e47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref12.C
@@ -0,0 +1,13 @@
+// PR c++/113141
+
+struct Matrix { };
+
+struct TPoint3 { operator const Matrix(); };
+
+void f(Matrix&);
+
+int main() {
+  TPoint3 X;
+  Matrix& m = (Matrix &)X;
+  f((Matrix &)X);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
new file mode 100644
index 000..f893f12dafa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
@@ -0,0 +1,16 @@
+// PR c++/113141
+// { dg-do compile { target c++11 } }
+
+struct ConvToRef {
+  operator int&();
+};
+
+struct A { int& r; };
+
+void f(A);
+
+int main() {
+  ConvToRef c;
+  A a{{c}};
+  f({{c}});
+}


Re: [PATCH] c++: problematic assert in reference_binding [PR113141]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 4/12/24 13:22, Patrick Palka wrote:
> > On Fri, 12 Apr 2024, Jason Merrill wrote:
> > 
> > > On 3/26/24 09:44, Patrick Palka wrote:
> > > > On Thu, 7 Mar 2024, Jason Merrill wrote:
> > > > 
> > > > > On 1/29/24 17:42, Patrick Palka wrote:
> > > > > > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > > > > > 
> > > > > > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does
> > > > > > > > > > > this
> > > > > > > > > > > look
> > > > > > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, but
> > > > > > > > > > > at
> > > > > > > > > > > least
> > > > > > > > > > > it safely fixes these testcases I guess.  Note that
> > > > > > > > > > > there's
> > > > > > > > > > > implementation disagreement about the second testcase, GCC
> > > > > > > > > > > always
> > > > > > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > > > > > 
> > > > > > > > > > Because of trying to initialize int& from {c}; removing the
> > > > > > > > > > extra
> > > > > > > > > > braces
> > > > > > > > > > makes it work everywhore.
> > > > > > > > > > 
> > > > > > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we
> > > > > > > > > > always
> > > > > > > > > > generate a
> > > > > > > > > > prvalue in this case, so perhaps we shouldn't recalculate if
> > > > > > > > > > the
> > > > > > > > > > initializer is an init-list?
> > > > > > > > > 
> > > > > > > > > ...but it seems bad to silently bind a const int& to a prvalue
> > > > > > > > > instead
> > > > > > > > > of
> > > > > > > > > directly to the reference returned by the operator, as clang
> > > > > > > > > does
> > > > > > > > > if
> > > > > > > > > we add
> > > > > > > > > const to the second testcase, so I think there's a defect in
> > > > > > > > > the
> > > > > > > > > standard
> > > > > > > > > here.
> > > > > > > > 
> > > > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > > > reference-related to E or scalar, ..."
> > > > > > > > 
> > > > > > > > > Maybe for now also disable the maybe_valid heuristics in the
> > > > > > > > > case
> > > > > > > > > of
> > > > > > > > > an
> > > > > > > > > init-list?
> > > > > > > > > 
> > > > > > > > > > The first testcase is special because it's a C-style cast;
> > > > > > > > > > seems
> > > > > > > > > > like the
> > > > > > > > > > maybe_valid = false heuristics should be disabled if
> > > > > > > > > > c_cast_p.
> > > > > > > 
> > > > > > > Thanks a lot for the pointers.  IIUC c_cast_p and
> > > > > > > LOOKUP_SHORTCUT_BAD_CONVS
> > > > > > > should already be mutually exclusive, since the latter is set only
> > > > > > > when
> > > > > > > computing argument conversions, so it shouldn't be necessary to
> > > > > > > check
> > > > > > > c_cast_p.
> > > > > > > 
> > > > > > >

Re: [PATCH 2/2] c++: remove lookup_template_class's entering_scope flag

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 5/1/24 12:41, Patrick Palka wrote:
> > On Fri, 2 Feb 2024, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux, does this look like
> > > an improvement?  This is not a bugfix and barely related to the previous
> > > patch, but the previous patch's new use of entering_scope=true motivated
> > > me to submit this patch since it seems like a nice simplification.
> > 
> > Ping, now that stage 1 is open.
> 
> Thanks for the ping.  The earlier message isn't showing up in Thunderbird for
> some reason, though I see it in the gmail web interface...

Ah, weird.  No worries, this patch was very much stage 1 material anyway.

> 
> > > @@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t
> > > complain, tree in_decl)
> > >   ctx = TREE_VEC_ELT (ctx, 0);
> > > }
> > >   else
> > > -   ctx = tsubst_aggr_type (ctx, args,
> > > -   complain | tf_qualifying_scope,
> > > -   in_decl, /*entering_scope=*/1);
> > > +   {
> > > + ctx = tsubst_scope (ctx, args, complain, in_decl);
> 
> Why is this one tsubst_scope while the others are all plain tsubst?

Ah, just because the call to tsubst_aggr_type being replace passes
tf_qualifying_scope already, so we might as well use tsubst_scope
as shorthand.

> 
> Do we want a tsubst_entering_scope function?

Which is just shorthand for tsubst + adjust_type_for_entering_scope?
Sure, though I was wondering if we eventually might want to get rid of
the distinction between the primary template type A and the generic
instantiation A, and we could treat this as an incremental step
towards that (then we'd just eventually remove the
adjust_type_for_entering_scope calls and keep the tsubst calls).

> 
> > > + ctx = adjust_type_for_entering_scope (ctx);
> 
> 



Re: [PATCH 2/2] c++: remove lookup_template_class's entering_scope flag

2024-05-01 Thread Patrick Palka
On Fri, 2 Feb 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux, does this look like
> an improvement?  This is not a bugfix and barely related to the previous
> patch, but the previous patch's new use of entering_scope=true motivated
> me to submit this patch since it seems like a nice simplification.

Ping, now that stage 1 is open.

> 
> -- >8 --
> 
> lookup_template_class's entering_scope flag controls whether to prefer
> returning the primary template type A instead of the corresponding
> implicit instantiation A.  When we want to set this flag as part of
> substitution, we need to use tsubst_aggr_type which also takes the flag,
> but this separate entry point to substitution turned out to be subtly
> problematic because it doesn't reuse typedefs like tsubst does, which
> r13-4729-gbe124477b38a71 fixed in a way that respects the flag after the
> fact, by adjusting the entering_scope=false result of
> lookup_template_class as if entering_scope=true was passed.
> 
> But if that's possible then it means lookup_template_class's the
> entering_scope flag is not necessary after all -- we can just do the
> after-the-fact adjustment everywhere that we currently pass
> entering_scope=true to it and tsubst_aggr_type.
> 
> To that end, this patch replaces this flag with an adjustment function
> adjust_type_for_entering_scope, to be used whereever we currently need
> the entering_scope=true behavior.  This means we can also get rid of
> tsubst_aggr_type, since the only reason we needed this entry point
> was to be able to pass entering_scope=true to lookup_template_class.
> 
> gcc/cp/ChangeLog:
> 
>   * coroutines.cc (instantiate_coro_traits): Adjust call to
>   lookup_template_class.
>   (instantiate_coro_handle_for_promise_type): Likewise.
>   * cp-tree.h (adjust_type_for_entering_scope): Declare.
>   (lookup_template_class): Adjust declaration.
>   * decl.cc (make_typename_type): Adjust call to
>   lookup_template_class. Likewise.
>   (get_tuple_size): Likewise.
>   (get_tuple_element_type): Likewise.
>   * pt.cc (adjust_type_for_entering_scope): Define.
>   (lookup_template_class): Remove entering_scope parameter.
>   Replace tsubst_aggr_type call with tsubst followed by
>   adjust_type_for_entering_scope.
>   (tsubst_aggr_type): Remove.
>   (tsubst_aggr_type_1): Inline into tsubst.
>   (tsubst_function_decl): Replace tsubst_aggr_type call
>   with tsubst followed by adjust_type_for_entering_scope.
>   (tsubst_template_decl): Likewise.
>   (tsubst_decl): Likewise.
>   (tsubst) :
>   Inlined from tsubst_aggr_type_1.
>   : Adjust calls to
>   lookup_template_class.
>   : Replace tsubst_aggr_type call with
>   tsubst tsubst_scope followed by adjust_type_for_entering_scope.
>   : Replace tsubst_aggr_type
>   call with tsubst followed by adjust_type_for_entering_scope.
>   Increment processing_template_decl when substituting the
>   context.
>   (tsubst_baselink): Replace tsubst_aggr_type call with tsubst
>   followed by adjust_type_for_entering_scope.
>   (tsubst_expr) : Replace tsubst_aggr_type
>   call with tsubst followed by adjust_type_for_entering_scope.
>   : Likewise.
>   (instantiate_template): Likewise.
>   (resolve_typename_type): Adjust lookup_template_class call
>   and call adjust_type_for_entering_scope afterward.
>   (listify): Adjust lookup_template_class call.
>   (alias_ctad_tweaks): Likewise.
>   * semantics.cc (finish_template_type): Adjust lookup_template_class
>   call and maybe call adjust_type_for_entering_scope afterward.
> ---
>  gcc/cp/coroutines.cc |   4 +-
>  gcc/cp/cp-tree.h |   3 +-
>  gcc/cp/decl.cc   |   4 +-
>  gcc/cp/pt.cc | 212 +--
>  gcc/cp/semantics.cc  |   4 +-
>  5 files changed, 91 insertions(+), 136 deletions(-)
> 
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index 3194c911e8c..8dab173d5cb 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc
> @@ -353,7 +353,7 @@ instantiate_coro_traits (tree fndecl, location_t kw)
>tree traits_class
>  = lookup_template_class (coro_traits_templ, targ,
>/*in_decl=*/NULL_TREE, /*context=*/NULL_TREE,
> -  /*entering scope=*/false, tf_warning_or_error);
> +  tf_warning_or_error);
>  
>if (traits_class == error_mark_node)
>  {
> @@ -400,7 +400,7 @@ instantiate_coro_handle_for_promise_type (location_t kw, 
> tree promise_type)
>  = lookup_template_class (coro_handle_identifier, targ,
>

Re: [PATCH 2/4] c++/modules: Track module purview for deferred instantiations [PR114630]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 5/1/24 08:54, Patrick Palka wrote:
> > On Thu, 2 May 2024, Nathaniel Shead wrote:
> > 
> > > On Wed, May 01, 2024 at 10:11:20AM -0400, Patrick Palka wrote:
> > > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > > > 
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > When calling instantiate_pending_templates at end of parsing, any new
> > > > > functions that are instantiated from this point have their module
> > > > > purview set based on the current value of module_kind.
> > > > > 
> > > > > This is unideal, however, as the modules code will then treat these
> > > > > instantiations as reachable and cause large swathes of the GMF to be
> > > > > emitted into the module CMI, despite no code in the actual module
> > > > > purview referencing it.
> > > > > 
> > > > > This patch fixes this by also remembering the value of module_kind
> > > > > when
> > > > > the instantiation was deferred, and restoring it when doing this
> > > > > deferred instantiation.  That way newly instantiated declarations
> > > > > appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
> > > > > instantiation was required, meaning that GMF entities won't be counted
> > > > > as reachable unless referenced by an actually reachable entity.
> > > > > 
> > > > > Note that purviewness and attachment etc. is generally only determined
> > > > > by the base template: this is purely for determining whether a
> > > > > specialisation was declared in the module purview and hence whether it
> > > > > should be streamed out.  See the comment on
> > > > > 'set_instantiating_module'.
> > > > > 
> > > > >   PR c++/114630
> > > > >   PR c++/114795
> > > > > 
> > > > > gcc/cp/ChangeLog:
> > > > > 
> > > > >   * cp-tree.h (struct tinst_level): Add field for tracking
> > > > >   module_kind.
> > > > >   * pt.cc (push_tinst_level_loc): Cache module_kind in
> > > > > new_level.
> > > > >   (reopen_tinst_level): Restore module_kind from level.
> > > > >   (instantiate_pending_templates): Save and restore module_kind
> > > > > so
> > > > >   it isn't affected by reopen_tinst_level.
> > > > 
> > > > LGTM.  Another approach is to instantiate all so-far deferred
> > > > instantiations and vtables once we reach the start of the module
> > > > purview, but your approach is much cleaner.
> > > > 
> > > > Note that deferred instantiation can induce more deferred instantiation,
> > > > but your approach will do the right thing here (module_kind will be
> > > > inherited from the point of instantiation).
> > > > 
> > > > What if an instantiation is needed from both the GMF and the module
> > > > purview?  Then IIUC it'll be instantiated as if from the GMF, which
> > > > seems right to me.
> > > > 
> > > 
> > > Hm..., so I believe it'll be marked according to whichever instantiates
> > > it "first", so if e.g. deferred from GMF and then instantiated
> > > non-deferred from purview it'll be marked purview (and the deferred
> > > instantiation will be skipped as it's already instantiated).  This could
> > > mean it gets unnecessarily emitted if it only got instantiated because
> > > it got used in e.g. a non-inline function body, I suppose; but that's
> > > true in general actually, at the moment.
> > 
> > FWIW I think the most relevant situation where we need to instantiate
> > immediately and can't defer until EOF is during constexpr evaluation of
> > a variable initializer.  (We also immediately instantiate variable
> > template specializations, and function template specializations with
> > deduced return type, but in these cases we'd always instantiate from the
> > first use, i.e. from the GMF in this scenario.)
> > 
> > So I guess a testcase for this situation could be something like:
> > 
> >  module;
> >  template constexpr int f(T t) { return t; }
> >  template int f(int);
> > 
> >  export module foo;
> >  constexpr int w = f(0);
> >  // f ideally shouldn't be emitted in the CMI?
> 
> Does the explicit instantiation change that at all?  Either way it seams like
> f and f aren't decl-reachable from w if we determine that after constant
> evaluation.

Currently due to the bug in question we handle this as if the explicit
instantiation was performed from the module purview:

  module;
  template constexpr int f(T t) { return t; }

  export module foo;
  template int f(int);
  constexpr int w = f(0);

I think we do want to emit f in that case?



Re: [PATCH 2/4] c++/modules: Track module purview for deferred instantiations [PR114630]

2024-05-01 Thread Patrick Palka
On Thu, 2 May 2024, Nathaniel Shead wrote:

> On Wed, May 01, 2024 at 10:11:20AM -0400, Patrick Palka wrote:
> > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > When calling instantiate_pending_templates at end of parsing, any new
> > > functions that are instantiated from this point have their module
> > > purview set based on the current value of module_kind.
> > > 
> > > This is unideal, however, as the modules code will then treat these
> > > instantiations as reachable and cause large swathes of the GMF to be
> > > emitted into the module CMI, despite no code in the actual module
> > > purview referencing it.
> > > 
> > > This patch fixes this by also remembering the value of module_kind when
> > > the instantiation was deferred, and restoring it when doing this
> > > deferred instantiation.  That way newly instantiated declarations
> > > appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
> > > instantiation was required, meaning that GMF entities won't be counted
> > > as reachable unless referenced by an actually reachable entity.
> > > 
> > > Note that purviewness and attachment etc. is generally only determined
> > > by the base template: this is purely for determining whether a
> > > specialisation was declared in the module purview and hence whether it
> > > should be streamed out.  See the comment on 'set_instantiating_module'.
> > > 
> > >   PR c++/114630
> > >   PR c++/114795
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * cp-tree.h (struct tinst_level): Add field for tracking
> > >   module_kind.
> > >   * pt.cc (push_tinst_level_loc): Cache module_kind in new_level.
> > >   (reopen_tinst_level): Restore module_kind from level.
> > >   (instantiate_pending_templates): Save and restore module_kind so
> > >   it isn't affected by reopen_tinst_level.
> > 
> > LGTM.  Another approach is to instantiate all so-far deferred
> > instantiations and vtables once we reach the start of the module
> > purview, but your approach is much cleaner.
> > 
> > Note that deferred instantiation can induce more deferred instantiation,
> > but your approach will do the right thing here (module_kind will be
> > inherited from the point of instantiation).
> > 
> > What if an instantiation is needed from both the GMF and the module
> > purview?  Then IIUC it'll be instantiated as if from the GMF, which
> > seems right to me.
> > 
> 
> Hm..., so I believe it'll be marked according to whichever instantiates
> it "first", so if e.g. deferred from GMF and then instantiated
> non-deferred from purview it'll be marked purview (and the deferred
> instantiation will be skipped as it's already instantiated).  This could
> mean it gets unnecessarily emitted if it only got instantiated because
> it got used in e.g. a non-inline function body, I suppose; but that's
> true in general actually, at the moment.

FWIW I think the most relevant situation where we need to instantiate
immediately and can't defer until EOF is during constexpr evaluation of
a variable initializer.  (We also immediately instantiate variable
template specializations, and function template specializations with
deduced return type, but in these cases we'd always instantiate from the
first use, i.e. from the GMF in this scenario.)

So I guess a testcase for this situation could be something like:

module;
template constexpr int f(T t) { return t; }
template int f(int);

export module foo;
constexpr int w = f(0);
// f ideally shouldn't be emitted in the CMI?

> 
> Maybe then a better approach would be to instead always use the
> DECL_MODULE_PURVIEW_P of the instantiating template instead of the
> global 'module_purview_p' function in 'set_instantiating_module'?
> I think that should still make sure that instantiations are emitted
> when they need to be (because they'll be reachable from a declaration
> in the purview): I might try to experiment with something like this.

The approach of instantiating all so-far deferred instantiations/vtables
at the start of the module purview should handle this properly too.

> 
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/modules/gmf-3.C: New test.
> > > 
> > > Signed-off-by: Nathaniel Shead 
> > > ---
> > >  gcc/cp/cp-tree.h |  3 +++
> > >  gcc/cp/pt.cc |  4 ++

Re: [PATCH 3/4] c++/modules: Also track module purview from deferred vtable instantiation [PR114630]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

LGTM

> 
> -- >8 --
> 
> Similarly to in the previous commit, templated virtual functions are
> sometimes not instantiated until after parsing has completed.  This
> means that any new declarations they instantiate are incorrectly marked
> as being in the module purview, causing them to not be discarded from
> the GMF.
> 
>   PR c++/114630
>   PR c++/114795
> 
> gcc/cp/ChangeLog:
> 
>   * decl2.cc (mark_vtable_entries): Set module purview of deferred
>   instantiations from the function decl.
>   (c_parse_final_cleanups): Save and restore module_kind.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/gmf-4.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/decl2.cc  | 11 +--
>  gcc/testsuite/g++.dg/modules/gmf-4.C | 27 +++
>  2 files changed, 36 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/gmf-4.C
> 
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index 806a2a4bc69..0115a6b1cc9 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -2210,6 +2210,11 @@ mark_vtable_entries (tree decl, vec 
> _vtables)
>   location, as we're called from c_parse_final_cleanups, which
>   takes care of that.  */
>input_location = DECL_SOURCE_LOCATION (fn);
> +  /* Similarly, any deferred instantiations should have the same
> +  module purview as this function.  */
> +  module_kind &= ~MK_PURVIEW;
> +  if (DECL_LANG_SPECIFIC (fn) && DECL_MODULE_PURVIEW_P (fn))
> + module_kind |= MK_PURVIEW;
>mark_used (fn);
>  }
>  }
> @@ -5085,6 +5090,7 @@ c_parse_final_cleanups (void)
>tree decl;
>  
>locus_at_end_of_parsing = input_location;
> +  unsigned module_kind_at_end_of_parsing = module_kind;
>/* We're done parsing.  */
>at_eof = 1;
>  
> @@ -5177,9 +5183,10 @@ c_parse_final_cleanups (void)
>   reconsider = true;
>   keyed_classes->unordered_remove (i);
> }
> -  /* The input_location may have been changed during marking of
> -  vtable entries.  */
> +  /* The input_location and module_kind may have been changed
> +  during marking of vtable entries.  */
>input_location = locus_at_end_of_parsing;
> +  module_kind = module_kind_at_end_of_parsing;
>  
>/* Write out needed type info variables.  We have to be careful
>looping through unemitted decls, because emit_tinfo_decl may
> diff --git a/gcc/testsuite/g++.dg/modules/gmf-4.C 
> b/gcc/testsuite/g++.dg/modules/gmf-4.C
> new file mode 100644
> index 000..c95bc782cea
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/gmf-4.C
> @@ -0,0 +1,27 @@
> +// PR c++/114630
> +// { dg-additional-options "-fmodules-ts -Wno-global-module 
> -fdump-lang-module" }
> +// { dg-module-cmi M }
> +
> +// Deferred instantiation of GM virtual functions should not place
> +// newly discovered declarations in the module purview
> +
> +module;
> +
> +template 
> +void go() {
> +  extern T fn_decl();
> +}
> +
> +template 
> +struct S {
> +  virtual void f() {
> +go();
> +  }
> +};
> +
> +S s;
> +
> +export module M;
> +
> +// The whole GMF should be discarded here
> +// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }
> -- 
> 2.43.2
> 
> 



Re: [PATCH 2/4] c++/modules: Track module purview for deferred instantiations [PR114630]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> When calling instantiate_pending_templates at end of parsing, any new
> functions that are instantiated from this point have their module
> purview set based on the current value of module_kind.
> 
> This is unideal, however, as the modules code will then treat these
> instantiations as reachable and cause large swathes of the GMF to be
> emitted into the module CMI, despite no code in the actual module
> purview referencing it.
> 
> This patch fixes this by also remembering the value of module_kind when
> the instantiation was deferred, and restoring it when doing this
> deferred instantiation.  That way newly instantiated declarations
> appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
> instantiation was required, meaning that GMF entities won't be counted
> as reachable unless referenced by an actually reachable entity.
> 
> Note that purviewness and attachment etc. is generally only determined
> by the base template: this is purely for determining whether a
> specialisation was declared in the module purview and hence whether it
> should be streamed out.  See the comment on 'set_instantiating_module'.
> 
>   PR c++/114630
>   PR c++/114795
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (struct tinst_level): Add field for tracking
>   module_kind.
>   * pt.cc (push_tinst_level_loc): Cache module_kind in new_level.
>   (reopen_tinst_level): Restore module_kind from level.
>   (instantiate_pending_templates): Save and restore module_kind so
>   it isn't affected by reopen_tinst_level.

LGTM.  Another approach is to instantiate all so-far deferred
instantiations and vtables once we reach the start of the module
purview, but your approach is much cleaner.

Note that deferred instantiation can induce more deferred instantiation,
but your approach will do the right thing here (module_kind will be
inherited from the point of instantiation).

What if an instantiation is needed from both the GMF and the module
purview?  Then IIUC it'll be instantiated as if from the GMF, which
seems right to me.

> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/gmf-3.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/cp-tree.h |  3 +++
>  gcc/cp/pt.cc |  4 
>  gcc/testsuite/g++.dg/modules/gmf-3.C | 13 +
>  3 files changed, 20 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/modules/gmf-3.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 1938ada0268..0e619120ccc 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6626,6 +6626,9 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
>/* The location where the template is instantiated.  */
>location_t locus;
>  
> +  /* The module kind where the template is instantiated. */
> +  unsigned module_kind;
> +
>/* errorcount + sorrycount when we pushed this level.  */
>unsigned short errors;
>  
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1c3eef60c06..401aa92bc3e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -11277,6 +11277,7 @@ push_tinst_level_loc (tree tldcl, tree targs, 
> location_t loc)
>new_level->tldcl = tldcl;
>new_level->targs = targs;
>new_level->locus = loc;
> +  new_level->module_kind = module_kind;
>new_level->errors = errorcount + sorrycount;
>new_level->next = NULL;
>new_level->refcount = 0;
> @@ -11345,6 +11346,7 @@ reopen_tinst_level (struct tinst_level *level)
>for (t = level; t; t = t->next)
>  ++tinst_depth;
>  
> +  module_kind = level->module_kind;
>set_refcount_ptr (current_tinst_level, level);
>pop_tinst_level ();
>if (current_tinst_level)
> @@ -27442,6 +27444,7 @@ instantiate_pending_templates (int retries)
>  {
>int reconsider;
>location_t saved_loc = input_location;
> +  unsigned saved_module_kind = module_kind;
>  
>/* Instantiating templates may trigger vtable generation.  This in turn
>   may require further template instantiations.  We place a limit here
> @@ -27532,6 +27535,7 @@ instantiate_pending_templates (int retries)
>while (reconsider);
>  
>input_location = saved_loc;
> +  module_kind = saved_module_kind;
>  }
>  
>  /* Substitute ARGVEC into T, which is a list of initializers for
> diff --git a/gcc/testsuite/g++.dg/modules/gmf-3.C 
> b/gcc/testsuite/g++.dg/modules/gmf-3.C
> new file mode 100644
> index 000..e52ae904ea9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/gmf-3.C
> @@ -0,0 +1,13 @@
> +// PR c++/114630
> +// { dg-additional-options "-fmodules-ts -Wno-global-module 
> -fdump-lang-module" }
> +// { dg-module-cmi M }
> +
> +module;
> +template  struct allocator {
> +  allocator() {}
> +};
> +template class allocator;
> +export module M;
> +
> +// The whole GMF should be discarded here
> +// { dg-final { scan-lang-dump "Wrote 0 clusters" module 

Re: [PATCH] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-01 Thread Patrick Palka


On Wed, 1 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk (and
> later 14.2)?  I don't think making it a GTY root is necessary but I felt
> perhaps better to be safe than sorry.
> 
> Potentially another approach would be to use DECL_UID instead like how
> entity_map does; would that be preferable?
> 
> -- >8 --
> 
> I got notified by Linaro CI and by checking testresults that there seems
> to be some occasional failures in tpl-friend-4_b.C on some architectures
> and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
> to reproduce but looking at the backtrace I suspect the issue is that
> we're adding to the 'imported_temploid_friend' map a decl that is
> ultimately discarded, which then has its address reused by a later decl
> causing a failure in the assert in 'set_originating_module'.
> 
> This patch attempts to fix the issue in two ways: by ensuring that we
> only store the decl if we know it's a new decl (and hence won't be
> discarded), and by making the imported_temploid_friends map a GTY root
> so that even if the decl does get discarded later the address isn't
> reused.
> 
> gcc/cp/ChangeLog:
> 
>   * module.cc (imported_temploid_friends): Mark GTY, and...
>   (init_modules): ...allocate from GGC.
>   (trees_in::decl_value): Only write to imported_temploid_friends
>   for new decls.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/module.cc | 7 ---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 5b8ff5bc483..37d38bb9654 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
> need to be attached to the same module as the temploid.  This maps
> these decls to the temploid they are instantiated them, as there is
> no other easy way to get this information.  */
> -static hash_map *imported_temploid_friends;
> +static GTY(()) hash_map *imported_temploid_friends;
>  
>  //
>  /* Tree streaming.   The tree streaming is very specific to the tree
> @@ -8327,7 +8327,8 @@ trees_in::decl_value ()
>if (TREE_CODE (inner) == FUNCTION_DECL
>|| TREE_CODE (inner) == TYPE_DECL)
>  if (tree owner = tree_node ())
> -  imported_temploid_friends->put (decl, owner);
> +  if (is_new)
> + imported_temploid_friends->put (decl, owner);

Hmm, I'm not seeing this code path getting reached for tpl-friend-4_b.C.
It seems we're instead adding to imported_temploid_friends from
propagate_defining_module, during tsubst_friend_function.

What seems to be happening is that we we first tsubst_friend_function
'foo' from TPL, and then we tsubst_friend_function 'foo' from DEF,
which ends up calling duplicate_decls, which ggc_frees this 'foo'
redeclaration that is still present in the imported_temploid_friends map.

So I don't think marking imported_temploid_friends as a GC root would
help with this situation.  If we want to keep imported_temploid_friends
as a tree -> tree map, I think we just need to ensure that a decl
is removed from the map upon getting ggc_free'd from e.g.  duplicate_decls.

But it seems simpler to use DECL_UID as the key instead, since those
never get reused even after the decl gets ggc_free'd IIUC.

>  
>/* Regular typedefs will have a NULL TREE_TYPE at this point.  */
>unsigned tdef_flags = 0;
> @@ -20523,7 +20524,7 @@ init_modules (cpp_reader *reader)
>entity_map = new entity_map_t (EXPERIMENT (1, 400));
>vec_safe_reserve (entity_ary, EXPERIMENT (1, 400));
>imported_temploid_friends
> - = new hash_map (EXPERIMENT (1, 400));
> + = hash_map::create_ggc (EXPERIMENT (1, 400));
>  }
>  
>  #if CHECKING_P
> -- 
> 2.43.2
> 
> 



[gcc r15-57] c++/modules: imported spec befriending class tmpl [PR114889]

2024-04-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:22b20ac6c6aead2d3f36c413a77dd0b80adfec39

commit r15-57-g22b20ac6c6aead2d3f36c413a77dd0b80adfec39
Author: Patrick Palka 
Date:   Mon Apr 29 21:27:59 2024 -0400

c++/modules: imported spec befriending class tmpl [PR114889]

When adding to CLASSTYPE_BEFRIENDING_CLASSES as part of installing an
imported class definition, we need to look through TEMPLATE_DECL like
make_friend_class does.

Otherwise in the below testcase we won't add _Hashtable to
CLASSTYPE_BEFRIENDING_CLASSES of _Map_base, which leads to a bogus
access check failure for _M_hash_code.

PR c++/114889

gcc/cp/ChangeLog:

* module.cc (trees_in::read_class_def): Look through
TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-8_a.H: New test.
* g++.dg/modules/friend-8_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc  |  2 ++
 gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++
 gcc/testsuite/g++.dg/modules/friend-8_b.C |  9 +
 3 files changed, 34 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c35e70b8cb8..3bf863e15d4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12498,6 +12498,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
 
  if (CLASS_TYPE_P (f))
{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}


[gcc r14-10149] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

2024-04-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:3c925ac349b03ae9439c632fb1c042cdc8d78f40

commit r14-10149-g3c925ac349b03ae9439c632fb1c042cdc8d78f40
Author: Patrick Palka 
Date:   Mon Apr 29 21:14:18 2024 -0400

c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

In the sizeof / sizeof operator expression handling we're missing
a dependence check for the second operand.

PR c++/114888

gcc/cp/ChangeLog:

* typeck.cc (cp_build_binary_op) : Add missing
dependence check for the second sizeof operand.

gcc/testsuite/ChangeLog:

* g++.dg/template/sizeof19.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 3900e944b0ac9db77380c5bb8635977dfd3b0691)

Diff:
---
 gcc/cp/typeck.cc | 1 +
 gcc/testsuite/g++.dg/template/sizeof19.C | 8 
 2 files changed, 9 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e5a52dc2b39..a25f8622651 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t ,
  if (!TYPE_P (type1))
type1 = TREE_TYPE (type1);
  if (type0
+ && type1
  && INDIRECT_TYPE_P (type0)
  && same_type_p (TREE_TYPE (type0), type1))
{
diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C 
b/gcc/testsuite/g++.dg/template/sizeof19.C
new file mode 100644
index 000..a1467995a9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sizeof19.C
@@ -0,0 +1,8 @@
+// PR c++/114888
+
+template
+struct A {
+  struct B {} *b;
+  static const int c = sizeof (b) / sizeof (b[0]);
+};
+const int d = A::c;


[gcc r15-56] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

2024-04-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:3900e944b0ac9db77380c5bb8635977dfd3b0691

commit r15-56-g3900e944b0ac9db77380c5bb8635977dfd3b0691
Author: Patrick Palka 
Date:   Mon Apr 29 21:14:18 2024 -0400

c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

In the sizeof / sizeof operator expression handling we're missing
a dependence check for the second operand.

PR c++/114888

gcc/cp/ChangeLog:

* typeck.cc (cp_build_binary_op) : Add missing
dependence check for the second sizeof operand.

gcc/testsuite/ChangeLog:

* g++.dg/template/sizeof19.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/typeck.cc | 1 +
 gcc/testsuite/g++.dg/template/sizeof19.C | 8 
 2 files changed, 9 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e5a52dc2b39..a25f8622651 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t ,
  if (!TYPE_P (type1))
type1 = TREE_TYPE (type1);
  if (type0
+ && type1
  && INDIRECT_TYPE_P (type0)
  && same_type_p (TREE_TYPE (type0), type1))
{
diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C 
b/gcc/testsuite/g++.dg/template/sizeof19.C
new file mode 100644
index 000..a1467995a9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sizeof19.C
@@ -0,0 +1,8 @@
+// PR c++/114888
+
+template
+struct A {
+  struct B {} *b;
+  static const int c = sizeof (b) / sizeof (b[0]);
+};
+const int d = A::c;


[PATCH] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

2024-04-29 Thread Patrick Palka
Lightly tested on x86_64-pc-linux-gnu so far, does this look OK for
trunk/14.1 after bootstrap+regtest finishes?

-- >8 --

We're missing a dependence check for the second operand in the
sizeof / sizeof handling.

PR c++/114888

gcc/cp/ChangeLog:

* typeck.cc (cp_build_binary_op) : Add missing
dependence check for the second sizeof operand.

gcc/testsuite/ChangeLog:

* g++.dg/template/sizeof19.C: New test.
---
 gcc/cp/typeck.cc | 1 +
 gcc/testsuite/g++.dg/template/sizeof19.C | 8 
 2 files changed, 9 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/sizeof19.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e5a52dc2b39..a25f8622651 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t ,
  if (!TYPE_P (type1))
type1 = TREE_TYPE (type1);
  if (type0
+ && type1
  && INDIRECT_TYPE_P (type0)
  && same_type_p (TREE_TYPE (type0), type1))
{
diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C 
b/gcc/testsuite/g++.dg/template/sizeof19.C
new file mode 100644
index 000..a1467995a9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sizeof19.C
@@ -0,0 +1,8 @@
+// PR c++/114888
+
+template
+struct A {
+  struct B {} *b;
+  static const int c = sizeof (b) / sizeof (b[0]);
+};
+const int d = A::c;
-- 
2.45.0.rc1



[PATCH] c++/modules: imported spec befriending class tmpl [PR114889]

2024-04-29 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk and perhaps
14 (I guess after 14.1 is released)?

-- >8 --

We need to look through TEMPLATE_DECL like make_friend_class does when
adding to CLASSTYPE_BEFRIENDING_CLASSES.

Otherwise in the below testcase we won't add _Hashtable to
CLASSTYPE_BEFRIENDING_CLASSES of _Map_base when installing the definition
of the former which leads to access control issues.

PR c++/114889

gcc/cp/ChangeLog:

* module.cc (trees_in::read_class_def): Look through
TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-8_a.H: New test.
* g++.dg/modules/friend-8_b.C: New test.
---
 gcc/cp/module.cc  |  2 ++
 gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++
 gcc/testsuite/g++.dg/modules/friend-8_b.C |  9 +
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/friend-8_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/friend-8_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7e654305f0a..3b2ba40c92b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12518,6 +12518,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
 
  if (CLASS_TYPE_P (f))
{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}
-- 
2.45.0.rc1



[gcc r14-10140] c++: fix source printing for "required from here" message

2024-04-26 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:c014cfd8853240827feb3a4cef92403e83cd4265

commit r14-10140-gc014cfd8853240827feb3a4cef92403e83cd4265
Author: Patrick Palka 
Date:   Fri Apr 26 07:44:25 2024 -0400

c++: fix source printing for "required from here" message

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
(added in r14-4388-g1c45319b66edc9) since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test 
(42); // { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |   
~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test (42); // { dg-message " required from here" }
  |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

gcc/cp/ChangeLog:

* error.cc (print_instantiation_partial_context_line): Clear the
pretty printer prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: Expect source line printed
for the "required from here" message.
* g++.dg/template/error60a.C: New test.

(cherry picked from commit 7d5479a2ecf6309281de10b747a7423169a2ff95)

Diff:
---
 gcc/cp/error.cc |  2 ++
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 +++-
 gcc/testsuite/g++.dg/template/error60a.C| 46 +
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..37987ccb570 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
 }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, _loc, DK_NOTE);
+  pp_set_prefix (context->printer, saved_prefix);
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@ void
 baz()
 {
   bar(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output &

Re: [PATCH] c++: fix source printing for "required from here" message

2024-04-26 Thread Patrick Palka
On Thu, 25 Apr 2024, David Malcolm wrote:

> On Wed, 2024-04-24 at 17:05 -0400, Patrick Palka wrote:
> > On Wed, 24 Apr 2024, Jason Merrill wrote:
> > 
> > > On 4/24/24 13:22, Patrick Palka wrote:
> > > > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in
> > > > progress,
> > > > does this look OK if successful?
> > > > 
> > > > -- >8 --
> > > > 
> > > > It seems the diagnostic machinery's source line printing respects
> > > > the pretty printer prefix, but this is undesirable for the call
> > > > to
> > > > diagnostic_show_locus in print_instantiation_partial_context_line
> > > > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > > > set when issuing an earlier, unrelated diagnostic and we just
> > > > want
> > > > to print an unprefixed source line.
> > > > 
> > > > This patch naively fixes this by clearing the prefix before
> > > > calling
> > > > diagnostic_show_locus.
> > > > 
> > > > Before this patch, for error60a.C below we'd print
> > > > 
> > > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > > usage()’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > > ‘unrelated_error’ was
> > > > not declared in this scope
> > > >     24 |   unrelated_error; // { dg-error "not declared" }
> > > >    |   ^~~
> > > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > > ‘void
> > > > test(Foo) [with Foo = int]’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > > here
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |  
> > > > test
> > > > (42); // { dg-message " required from here" }
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |
> > > > ~~^~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > > conversion
> > > > from ‘int’ to ‘int*’ [-fpermissive]
> > > >     19 |   my_pointer ptr (val); // { dg-error "invalid
> > > > conversion from
> > > > 'int' to 'int\\*'" }
> > > >    |    ^~~
> > > >    |    |
> > > >    |    int
> > > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > > initializing argument
> > > > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> > > >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > > argument 1"
> > > > }
> > > >    |   ~^~~
> > > > 
> > > > and afterward we print
> > > > 
> > > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > > usage()’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > > ‘unrelated_error’ was
> > > > not declared in this scope
> > > >     24 |   unrelated_error; // { dg-error "not declared" }
> > > >    |   ^~~
> > > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > > ‘void
> > > > test(Foo) [with Foo = int]’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > > here
> > > >     25 |   test (42); // { dg-message " required from here"
> > > > }
> > > >    |   ~~^~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > > conversion
> > > > from ‘int’ to ‘int*’ [-fpermissive]
> > > >     19 |   my_pointer ptr (val); // { dg-error "invalid
> > > > conversion from
> > > > 'int' to 'int\\*'" }
> > > >    |    ^~~
> > > >    |    |
> > > >    |    int
> > > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > > initializing argument
> > > > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> > > >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > > argument 1"
> > > > }
> > > >    |   ~^~~
> > > > 
> > > > gcc/cp/C

[gcc r15-4] c++: fix source printing for "required from here" message

2024-04-26 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:7d5479a2ecf6309281de10b747a7423169a2ff95

commit r15-4-g7d5479a2ecf6309281de10b747a7423169a2ff95
Author: Patrick Palka 
Date:   Fri Apr 26 07:44:25 2024 -0400

c++: fix source printing for "required from here" message

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
(added in r14-4388-g1c45319b66edc9) since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test 
(42); // { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |   
~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test (42); // { dg-message " required from here" }
  |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

gcc/cp/ChangeLog:

* error.cc (print_instantiation_partial_context_line): Clear the
pretty printer prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: Expect source line printed
for the "required from here" message.
* g++.dg/template/error60a.C: New test.

Diff:
---
 gcc/cp/error.cc |  2 ++
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 +++-
 gcc/testsuite/g++.dg/template/error60a.C| 46 +
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..37987ccb570 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
 }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, _loc, DK_NOTE);
+  pp_set_prefix (context->printer, saved_prefix);
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@ void
 baz()
 {
   bar(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output "for no match error" }
+   bar();
+   ^~
+   { dg-end-m

[gcc r14-10111] c++/modules testsuite: restrict expensive pr99023 test

2024-04-24 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:26a3edbe2357cf975f345ad1b59b9f9a3444316e

commit r14-10111-g26a3edbe2357cf975f345ad1b59b9f9a3444316e
Author: Patrick Palka 
Date:   Wed Apr 24 17:51:54 2024 -0400

c++/modules testsuite: restrict expensive pr99023 test

The pr99023 testcase uses --param=ggc-min-expand=0 which forces a GC
during every collection point and consequently is very slow to run,
and ends up being the main bottleneck of the modules.exp testsuite.

So this patch restricts this test to run once, in C++20 mode, instead of
multiple times (C++17, C++20 and C++23 mode by default).  After this
patch the modules.exp testsuite finishes in 3m instead of 3m40s with -j8
on my machine.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99023_a.X: Run only in C++20 mode.
* g++.dg/modules/pr99023_b.X: Likewise.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/testsuite/g++.dg/modules/pr99023_a.X | 1 +
 gcc/testsuite/g++.dg/modules/pr99023_b.X | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X 
b/gcc/testsuite/g++.dg/modules/pr99023_a.X
index c872d15f792..507e9569535 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X 
b/gcc/testsuite/g++.dg/modules/pr99023_b.X
index ca5f32e5bcc..59d32bee8d5 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }


[gcc r14-10110] c++: constexpr union member access folding [PR114709]

2024-04-24 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:0844170e9ef60a8b2f6fba6786672f30ce1c2749

commit r14-10110-g0844170e9ef60a8b2f6fba6786672f30ce1c2749
Author: Patrick Palka 
Date:   Wed Apr 24 17:49:56 2024 -0400

c++: constexpr union member access folding [PR114709]

The object/offset canonicalization performed in cxx_fold_indirect_ref
is undesirable for union member accesses because it loses information
about the member being accessed which we may later need to diagnose an
inactive-member access.  So this patch restricts the canonicalization
accordingly.

PR c++/114709

gcc/cp/ChangeLog:

* constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset
canonicalization to RECORD_TYPE member accesses.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union8.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constexpr.cc   | 3 +++
 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 
 2 files changed, 11 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 302b266809f..2e83d24dfda 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5799,6 +5799,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, 
location_t loc, tree type,
  more folding opportunities.  */
   auto canonicalize_obj_off = [] (tree& obj, tree& off) {
 while (TREE_CODE (obj) == COMPONENT_REF
+  /* We need to preserve union member accesses so that we can
+ later properly diagnose accessing the wrong member.  */
+  && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE
   && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
   {
tree field = TREE_OPERAND (obj, 1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
new file mode 100644
index 000..34c264944b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
@@ -0,0 +1,8 @@
+// PR c++/114709
+// { dg-do compile { target c++11 } }
+
+struct T1 { int a, b; };
+struct T2 { int c; double d; };
+union U { T1 t1; T2 t2; };
+
+constexpr int v = U{{1,2}}.t2.*::c; // { dg-error "accessing 'U::t2'" }


Re: [PATCH] c++: fix source printing for "required from here" message

2024-04-24 Thread Patrick Palka
On Wed, 24 Apr 2024, Jason Merrill wrote:

> On 4/24/24 13:22, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
> > does this look OK if successful?
> > 
> > -- >8 --
> > 
> > It seems the diagnostic machinery's source line printing respects
> > the pretty printer prefix, but this is undesirable for the call to
> > diagnostic_show_locus in print_instantiation_partial_context_line
> > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > set when issuing an earlier, unrelated diagnostic and we just want
> > to print an unprefixed source line.
> > 
> > This patch naively fixes this by clearing the prefix before calling
> > diagnostic_show_locus.
> > 
> > Before this patch, for error60a.C below we'd print
> > 
> > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was
> > not declared in this scope
> > 24 |   unrelated_error; // { dg-error "not declared" }
> >|   ^~~
> > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void
> > test(Foo) [with Foo = int]’:
> > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test
> > (42); // { dg-message " required from here" }
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |
> > ~~^~~~
> > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion
> > from ‘int’ to ‘int*’ [-fpermissive]
> > 19 |   my_pointer ptr (val); // { dg-error "invalid conversion from
> > 'int' to 'int\\*'" }
> >|^~~
> >||
> >|int
> > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument
> > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1"
> > }
> >|   ~^~~
> > 
> > and afterward we print
> > 
> > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was
> > not declared in this scope
> > 24 |   unrelated_error; // { dg-error "not declared" }
> >|   ^~~
> > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void
> > test(Foo) [with Foo = int]’:
> > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> > 25 |   test (42); // { dg-message " required from here" }
> >|   ~~^~~~
> > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion
> > from ‘int’ to ‘int*’ [-fpermissive]
> > 19 |   my_pointer ptr (val); // { dg-error "invalid conversion from
> > 'int' to 'int\\*'" }
> >|^~~
> >||
> >|int
> > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument
> > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1"
> > }
> >|   ~^~~
> > 
> > gcc/cp/ChangeLog:
> > 
> > * error.cc (print_instantiation_partial_context_line): Clear
> > context->printer->prefix around the call to diagnostic_show_locus.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/concepts/diagnostic2.C: Expect source line printed
> > for the required from here message.
> > * g++.dg/template/error60a.C: New test.
> > ---
> >   gcc/cp/error.cc |  2 +
> >   gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
> >   gcc/testsuite/g++.dg/template/error60a.C| 46 +
> >   3 files changed, 53 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/error60a.C
> > 
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index 7074845154e..a7067d4d2ed 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line
> > (diagnostic_context *context,
> >: _("required from here\n"));
> >   }
> > gcc_rich_location rich_loc (loc);
> > +  char *saved_prefix = pp_take_prefix (c

[PATCH] c++: fix source printing for "required from here" message

2024-04-24 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
does this look OK if successful?

-- >8 --

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
added in r14-4388-g1c45319b66edc9 since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not 
declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) 
[with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test (42); 
// { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from 
‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 
of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not 
declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) 
[with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test (42); // { dg-message " required from here" }
  |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from 
‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 
of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

gcc/cp/ChangeLog:

* error.cc (print_instantiation_partial_context_line): Clear
context->printer->prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: Expect source line printed
for the required from here message.
* g++.dg/template/error60a.C: New test.
---
 gcc/cp/error.cc |  2 +
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
 gcc/testsuite/g++.dg/template/error60a.C| 46 +
 3 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/error60a.C

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..a7067d4d2ed 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
 }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, _loc, DK_NOTE);
+  context->printer->prefix = saved_prefix;
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@ void
 baz()
 {
   bar(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output "for no match error" }
+   bar();
+   ^~
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "for required from here message" }
bar();
^~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/g++.dg/template/error60a.C 
b/gcc/testsuite/g++.dg/template/error60a.C
new file mode 100644
index 000..7c2f8188d16
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/error60a.C
@@ -0,0 +1,46 @@
+// Like error60.C but first issues an unrelated error that
+// causes the pretty printer prefix to get set, 

Re: [PATCH] c++: print source code in print_instantiation_partial_context_line

2024-04-24 Thread Patrick Palka
On Wed, 24 Apr 2024, Patrick Palka wrote:

> On Tue, 9 Apr 2024, Patrick Palka wrote:
> 
> > On Thu, 19 Oct 2023, Patrick Palka wrote:
> > 
> > > On Tue, 3 Oct 2023, David Malcolm wrote:
> > > 
> > > > As mentioned in my Cauldron talk, this patch adds a call to
> > > > diagnostic_show_locus to the "required from here" messages
> > > > in print_instantiation_partial_context_line, so that e.g., rather
> > > > than the rather mystifying:
> > > > 
> > > > In file included from 
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > > >  from ../../src/demo-1.C:1:
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > > ../../src/demo-1.C:15:32:   required from here
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > > error: no matching function for call to ‘bar::bar()’
> > > >  1066 | { return unique_ptr<_Tp>(new 
> > > > _Tp(std::forward<_Args>(__args)...)); }
> > > >   |  
> > > > ^~~
> > > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > > >10 |   bar (int);
> > > >   |   ^~~
> > > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 
> > > > provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const 
> > > > bar&)’
> > > > 7 | class bar : public foo
> > > >   |   ^~~
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > 
> > > > we emit:
> > > > 
> > > > In file included from 
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > > >  from ../../src/demo-1.C:1:
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > > ../../src/demo-1.C:15:32:   required from here
> > > >15 |   return std::make_unique ();
> > > >   |  ~~^~
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > > error: no matching function for call to ‘bar::bar()’
> > > >  1066 | { return unique_ptr<_Tp>(new 
> > > > _Tp(std::forward<_Args>(__args)...)); }
> > > >   |  
> > > > ^~~
> > > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > > >10 |   bar (int);
> > > >   |   ^~~
> > > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 
> > > > provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const 
> > > > bar&)’
> > > > 7 | class bar : public foo
> > > >   |   ^~~
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > 
> > > > which shows the code that's leading to the error (the bad call to
> > > > std::make_unique).
> > > 
> > > This is great!  I noticed however that the source code gets printed in a
> > > surprising way in some contexts.  Consider:
> > > 
> > > template void f(typename T::type);
> > > 
> > > int main() {
> > >   f(0);
> > > }
> > > 
> > > For this testcase we emit:
> > > 
> > > testcase.C: In function ‘int main()’:
> > > testcase.C:4:9: error: no matching function for call to ‘f(int)’
> > > 4 |   f(0);
> > >   

Re: [PATCH] c++: print source code in print_instantiation_partial_context_line

2024-04-24 Thread Patrick Palka
On Tue, 9 Apr 2024, Patrick Palka wrote:

> On Thu, 19 Oct 2023, Patrick Palka wrote:
> 
> > On Tue, 3 Oct 2023, David Malcolm wrote:
> > 
> > > As mentioned in my Cauldron talk, this patch adds a call to
> > > diagnostic_show_locus to the "required from here" messages
> > > in print_instantiation_partial_context_line, so that e.g., rather
> > > than the rather mystifying:
> > > 
> > > In file included from 
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > >  from ../../src/demo-1.C:1:
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > ../../src/demo-1.C:15:32:   required from here
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > error: no matching function for call to ‘bar::bar()’
> > >  1066 | { return unique_ptr<_Tp>(new 
> > > _Tp(std::forward<_Args>(__args)...)); }
> > >   |  
> > > ^~~
> > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > >10 |   bar (int);
> > >   |   ^~~
> > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const bar&)’
> > > 7 | class bar : public foo
> > >   |   ^~~
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > 
> > > we emit:
> > > 
> > > In file included from 
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > >  from ../../src/demo-1.C:1:
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > ../../src/demo-1.C:15:32:   required from here
> > >15 |   return std::make_unique ();
> > >   |  ~~^~
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > error: no matching function for call to ‘bar::bar()’
> > >  1066 | { return unique_ptr<_Tp>(new 
> > > _Tp(std::forward<_Args>(__args)...)); }
> > >   |  
> > > ^~~
> > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > >10 |   bar (int);
> > >   |   ^~~
> > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const bar&)’
> > > 7 | class bar : public foo
> > >   |   ^~~
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > 
> > > which shows the code that's leading to the error (the bad call to
> > > std::make_unique).
> > 
> > This is great!  I noticed however that the source code gets printed in a
> > surprising way in some contexts.  Consider:
> > 
> > template void f(typename T::type);
> > 
> > int main() {
> >   f(0);
> > }
> > 
> > For this testcase we emit:
> > 
> > testcase.C: In function ‘int main()’:
> > testcase.C:4:9: error: no matching function for call to ‘f(int)’
> > 4 |   f(0);
> >   |   ~~^~~
> > testcase.C:1:24: note: candidate: ‘template void f(typename 
> > T::type)’
> > 1 | template void f(typename T::type);
> >   |^
> > testcase.C:1:24: note:   template argument deduction/substitution failed:
> > testcase.C: In substitution of ‘template void f(typename T::type) 
> > [with T = int]’:
> > testcase.C:4:9:   required from here
> > testcase.C:1:24: note: 4 |   f(0);
> > testcase.C:1:24: note:   |   ~~^~~
> &

Re: [PATCH] c++/modules testsuite: avoid expensive ggc-min-expand=0

2024-04-24 Thread Patrick Palka
On Tue, 23 Apr 2024, Jason Merrill wrote:

> On 4/23/24 11:28, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> 
> Is the test being run for multiple standard levels?  I'd rather restrict it to
> one and keep fully testing GC-safety.

Ah yeah, looks like it runs three times by default, in C++17, C++20 and
C++23 mode.  Like so?  The speedup is almost as good as using
ggc-min-expand=1.

Interestingly, restricting to one standard level _and_ using
ggc-min-expand=1 does not give further speedup.

-- >8 --

Subject: [PATCH] c++/modules testsuite: restrict expensive pr99023 test

The pr99023 testcase uses --param=ggc-min-expand=0 which forces a GC
during every collection point and consequently is very slow to run,
and ends up being the main bottleneck of the modules.exp testsuite.

So this patch restricts this test to run once, in C++20 mode, instead of
multiple times (C++17, C++20 and C++23 mode by default).  After this
patch the modules.exp testsuite finishes in 3m instead of 3m40s with -j8
on my machine.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99023_a.X: Run only in C++20 mode.
* g++.dg/modules/pr99023_b.X: Likewise.
---
 gcc/testsuite/g++.dg/modules/pr99023_a.X | 1 +
 gcc/testsuite/g++.dg/modules/pr99023_b.X | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X 
b/gcc/testsuite/g++.dg/modules/pr99023_a.X
index c872d15f792..507e9569535 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X 
b/gcc/testsuite/g++.dg/modules/pr99023_b.X
index ca5f32e5bcc..59d32bee8d5 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }
-- 
2.45.0.rc0


> 
> > -- >8 --
> > 
> > The below testcase uses --param=ggc-min-expand=0 which forces a full GC
> > during every collection point and in turn takes over two minutes to run
> > and ends up being the main bottleneck of the modules.exp testsuite.
> > 
> > This patch speeds up this test without (hopefully) significantly affecting
> > its coverage by using =1 instead of =0 which forces a full GC each time the
> > heap grows by 1%, which means exponentially fewer GCs.  After this patch
> > the modules.exp testsuite finishes in 2m55s instead of 3m40s with -j8 on
> > my machine.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/modules/pr99023_a.X: Use ggc-min-expand=1 instead of =0.
> > * g++.dg/modules/pr99023_b.X: Likewise.
> > ---
> >   gcc/testsuite/g++.dg/modules/pr99023_a.X | 2 +-
> >   gcc/testsuite/g++.dg/modules/pr99023_b.X | 2 +-
> >   2 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > b/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > index c872d15f792..96bb4a2ab5a 100644
> > --- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > +++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > @@ -1,5 +1,5 @@
> >   // PR c++/99023, ICE
> > -// { dg-additional-options {-x c++-system-header initializer_list
> > -fmodules-ts --param ggc-min-expand=0} }
> > +// { dg-additional-options {-x c++-system-header initializer_list
> > -fmodules-ts --param ggc-min-expand=1} }
> > // { dg-prune-output {linker input file unused} }
> >   diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > b/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > index ca5f32e5bcc..955378ad88f 100644
> > --- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > +++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > @@ -1,5 +1,5 @@
> >   // PR c++/99023, ICE
> > -// { dg-additional-options {-x c++-system-header iostream -fmodules-ts
> > -flang-info-include-translate= --param ggc-min-expand=0} }
> > +// { dg-additional-options {-x c++-system-header iostream -fmodules-ts
> > -flang-info-include-translate= --param ggc-min-expand=1} }
> > // { dg-prune-output {linker input file unused} }
> >   
> 
> 



[PATCH] c++/modules testsuite: avoid expensive ggc-min-expand=0

2024-04-23 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

The below testcase uses --param=ggc-min-expand=0 which forces a full GC
during every collection point and in turn takes over two minutes to run
and ends up being the main bottleneck of the modules.exp testsuite.

This patch speeds up this test without (hopefully) significantly affecting
its coverage by using =1 instead of =0 which forces a full GC each time the
heap grows by 1%, which means exponentially fewer GCs.  After this patch
the modules.exp testsuite finishes in 2m55s instead of 3m40s with -j8 on
my machine.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99023_a.X: Use ggc-min-expand=1 instead of =0.
* g++.dg/modules/pr99023_b.X: Likewise.
---
 gcc/testsuite/g++.dg/modules/pr99023_a.X | 2 +-
 gcc/testsuite/g++.dg/modules/pr99023_b.X | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X 
b/gcc/testsuite/g++.dg/modules/pr99023_a.X
index c872d15f792..96bb4a2ab5a 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
@@ -1,5 +1,5 @@
 // PR c++/99023, ICE
-// { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=0} }
+// { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=1} }
 
 // { dg-prune-output {linker input file unused} }
 
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X 
b/gcc/testsuite/g++.dg/modules/pr99023_b.X
index ca5f32e5bcc..955378ad88f 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
@@ -1,5 +1,5 @@
 // PR c++/99023, ICE
-// { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=0} }
+// { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=1} }
 
 // { dg-prune-output {linker input file unused} }
 
-- 
2.45.0.rc0



[gcc r14-10096] c++/modules: deduced return type merging [PR114795]

2024-04-23 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:4f9401d1a802325e5dfa2db841945e1a9c59a980

commit r14-10096-g4f9401d1a802325e5dfa2db841945e1a9c59a980
Author: Patrick Palka 
Date:   Tue Apr 23 14:01:22 2024 -0400

c++/modules: deduced return type merging [PR114795]

When merging an imported function template specialization with an
existing one, if the existing one has an undeduced return type and the
imported one's is already deduced, we need to propagate the deduced type
since once we install the imported definition we won't get a chance to
deduce it by normal means.

So this patch makes is_matching_decl propagate the deduced return
type alongside our propagation of the exception specification.
Another option would be to propagate it later when installing the
imported definition from read_function_def, but it seems preferable
to do it sooner rather than later.

PR c++/114795

gcc/cp/ChangeLog:

* module.cc (trees_in::is_matching_decl): Propagate deduced
function return type.

gcc/testsuite/ChangeLog:

* g++.dg/modules/auto-4_a.H: New test.
* g++.dg/modules/auto-4_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc|  9 +
 gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++
 gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++
 3 files changed, 38 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d94d8ff4df9..c35e70b8cb8 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11537,6 +11537,15 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
   else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
   && !comp_except_specs (d_spec, e_spec, ce_type))
goto mismatch;
+
+  /* Similarly if EXISTING has an undeduced return type, but DECL's
+is already deduced.  */
+  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
+   {
+ dump (dumper::MERGE)
+   && dump ("Propagating deduced return type to %N", existing);
+ TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), 
e_type);
+   }
 }
   else if (is_typedef)
 {
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H 
b/gcc/testsuite/g++.dg/modules/auto-4_a.H
new file mode 100644
index 000..0f7cd262dfa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H
@@ -0,0 +1,14 @@
+// PR c++/114795
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct A {
+  auto f() { return T(); }
+};
+
+template
+void g() {
+  A a;
+  a.f();
+}
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C 
b/gcc/testsuite/g++.dg/modules/auto-4_b.C
new file mode 100644
index 000..378684ef6d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C
@@ -0,0 +1,15 @@
+// PR c++/114795
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+template
+struct A {
+  auto f() { return T(); }
+};
+
+A a;
+
+import "auto-4_a.H";
+
+int main() {
+  g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 }
+}


Re: [PATCH] c++/modules: deduced return type merging [PR114795]

2024-04-23 Thread Patrick Palka
On Tue, 23 Apr 2024, Patrick Palka wrote:
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> 
> -- >8 --
> 
> When merging an imported function template specialization with an
> existing one, if the existing one has an undeduced return type and the
> imported one's is already deduced, we need to propagate the deduced type
> since once we install the imported definition we won't get a chance to
> deduce it by normal means.
> 
> This patch makes is_matching_decl propagate the deduced return type
> alongside the existing propagate of the existing specification.  I

er, "alongside the existing propagation of the exception specification".

> suppose could instead propagate it later when installing the imported
> definition from read_definition, but it seems best to propagate it
> sooner rather than later.
> 
>   PR c++/114795
> 
> gcc/cp/ChangeLog:
> 
>   * module.cc (trees_in::is_matching_decl): Propagate deduced
>   function return type.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/auto-4_a.H: New test.
>   * g++.dg/modules/auto-4_b.C: New test.
> ---
>  gcc/cp/module.cc|  5 +
>  gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++
>  gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++
>  3 files changed, 34 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_a.H
>  create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_b.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index d94d8ff4df9..e10e19ac9f7 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -11537,6 +11537,11 @@ trees_in::is_matching_decl (tree existing, tree 
> decl, bool is_typedef)
>else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
>  && !comp_except_specs (d_spec, e_spec, ce_type))
>   goto mismatch;
> +
> +  /* Similarly if EXISTING has an undeduced return type, but DECL's
> +  is already deduced.  */
> +  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
> + TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
>  }
>else if (is_typedef)
>  {
> diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H 
> b/gcc/testsuite/g++.dg/modules/auto-4_a.H
> new file mode 100644
> index 000..52b50533982
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H
> @@ -0,0 +1,14 @@
> +// PR c++/114795
> +// { dg-additional-options "-fmodule-header" }
> +// { dg-module-cmi {} }
> +
> +template
> +struct A {
> +  auto f() { return 0; }

Oops, this should be "return T();" to match the other definition below.

> +};
> +
> +template
> +inline void g() {
> +  A a;
> +  a.f();
> +}
> diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C 
> b/gcc/testsuite/g++.dg/modules/auto-4_b.C
> new file mode 100644
> index 000..378684ef6d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C
> @@ -0,0 +1,15 @@
> +// PR c++/114795
> +// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
> +
> +template
> +struct A {
> +  auto f() { return T(); }
> +};
> +
> +A a;
> +
> +import "auto-4_a.H";
> +
> +int main() {
> +  g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 
> }
> +}
> -- 
> 2.45.0.rc0
> 
> 



[PATCH] c++/modules: deduced return type merging [PR114795]

2024-04-23 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

When merging an imported function template specialization with an
existing one, if the existing one has an undeduced return type and the
imported one's is already deduced, we need to propagate the deduced type
since once we install the imported definition we won't get a chance to
deduce it by normal means.

This patch makes is_matching_decl propagate the deduced return type
alongside the existing propagate of the existing specification.  I
suppose could instead propagate it later when installing the imported
definition from read_definition, but it seems best to propagate it
sooner rather than later.

PR c++/114795

gcc/cp/ChangeLog:

* module.cc (trees_in::is_matching_decl): Propagate deduced
function return type.

gcc/testsuite/ChangeLog:

* g++.dg/modules/auto-4_a.H: New test.
* g++.dg/modules/auto-4_b.C: New test.
---
 gcc/cp/module.cc|  5 +
 gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++
 gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d94d8ff4df9..e10e19ac9f7 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11537,6 +11537,11 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
   else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
   && !comp_except_specs (d_spec, e_spec, ce_type))
goto mismatch;
+
+  /* Similarly if EXISTING has an undeduced return type, but DECL's
+is already deduced.  */
+  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
+   TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
 }
   else if (is_typedef)
 {
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H 
b/gcc/testsuite/g++.dg/modules/auto-4_a.H
new file mode 100644
index 000..52b50533982
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H
@@ -0,0 +1,14 @@
+// PR c++/114795
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct A {
+  auto f() { return 0; }
+};
+
+template
+inline void g() {
+  A a;
+  a.f();
+}
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C 
b/gcc/testsuite/g++.dg/modules/auto-4_b.C
new file mode 100644
index 000..378684ef6d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C
@@ -0,0 +1,15 @@
+// PR c++/114795
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+template
+struct A {
+  auto f() { return T(); }
+};
+
+A a;
+
+import "auto-4_a.H";
+
+int main() {
+  g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 }
+}
-- 
2.45.0.rc0



[PATCH] c++: constexpr union member access folding [PR114709]

2024-04-22 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk/13/12?

-- >8 --

The object/offset canonicalization performed in cxx_fold_indirect_ref
is undesirable for union member accesses because it loses information
about the member being accessed which we may later need to diagnose an
inactive-member access.  So this patch restricts the canonicalization
accordingly.

PR c++/114709

gcc/cp/ChangeLog:

* constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset
canonicalization to RECORD_TYPE member accesses.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union8.C: New test.
---
 gcc/cp/constexpr.cc   | 1 +
 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 
 2 files changed, 9 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fcc847d85df..941a478e889 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5797,6 +5797,7 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, 
location_t loc, tree type,
  more folding opportunities.  */
   auto canonicalize_obj_off = [] (tree& obj, tree& off) {
 while (TREE_CODE (obj) == COMPONENT_REF
+  && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE
   && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
   {
tree field = TREE_OPERAND (obj, 1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
new file mode 100644
index 000..34c264944b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
@@ -0,0 +1,8 @@
+// PR c++/114709
+// { dg-do compile { target c++11 } }
+
+struct T1 { int a, b; };
+struct T2 { int c; double d; };
+union U { T1 t1; T2 t2; };
+
+constexpr int v = U{{1,2}}.t2.*::c; // { dg-error "accessing 'U::t2'" }
-- 
2.45.0.rc0



[PATCH] libstdc++: Implement ranges::concat_view from P2542R7

2024-04-22 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  More tests
are needed but I figured I'd submit this now for possible consideration into
GCC 14 since we're getting close to release..  All changes are confined to
C++26.

-- >8 --

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_concat): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__concat_reference_t): Define
for C++26.
(__detail::__concat_value_t): Likewise.
(__detail::__concat_rvalue_reference_t): Likewise.
(__detail::__concat_indirectly_readable_impl): Likewise.
(__detail::__concat_indirectly_readable): Likewise.
(__detail::__concatable): Likewise.
(__detail::__all_but_last_common): Likewise.
(__detail::__concat_is_random_access): Likewise.
(__detail::__concat_is_bidirectional): Likewise.
(__detail::__last_is_common): Likewise.
(concat_view): Likewise.
(__detail::__concat_view_iter_cat): Likewise.
(concat_view::iterator): Likewise.
(views::__detail::__can_concat_view): Likewise.
(views::_Concat, views::concat): Likewise.
* testsuite/std/ranges/concat/1.cc: New test.
---
 libstdc++-v3/include/bits/version.def |   8 +
 libstdc++-v3/include/bits/version.h   |  10 +
 libstdc++-v3/include/std/ranges   | 584 ++
 libstdc++-v3/testsuite/std/ranges/concat/1.cc |  61 ++
 4 files changed, 663 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/concat/1.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 5c0477fb61e..af13090c094 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1796,6 +1796,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_concat;
+  values = {
+v = 202403;
+cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 65e708c73fb..1f27bfe050d 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2003,4 +2003,14 @@
 #endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
 #undef __glibcxx_want_to_string
 
+#if !defined(__cpp_lib_ranges_concat)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_concat 202403L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
+#   define __cpp_lib_ranges_concat 202403L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_concat) && 
defined(__glibcxx_want_ranges_concat) */
+#undef __glibcxx_want_ranges_concat
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index afce818376b..28a39bf6f34 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -55,6 +55,7 @@
 #define __glibcxx_want_ranges_as_const
 #define __glibcxx_want_ranges_as_rvalue
 #define __glibcxx_want_ranges_cartesian_product
+#define __glibcxx_want_ranges_concat
 #define __glibcxx_want_ranges_chunk
 #define __glibcxx_want_ranges_chunk_by
 #define __glibcxx_want_ranges_enumerate
@@ -9514,6 +9515,589 @@ namespace __detail
 } // namespace ranges
 #endif // __cpp_lib_ranges_to_container
 
+#if __cpp_lib_ranges_concat // C++ >= C++26
+namespace ranges
+{
+  namespace __detail
+  {
+template
+  using __concat_reference_t = 
common_reference_t...>;
+
+template
+  using __concat_value_t = common_type_t...>;
+
+template
+  using __concat_rvalue_reference_t
+   = common_reference_t...>;
+
+template
+  concept __concat_indirectly_readable_impl = requires (const _It __it) {
+   { *__it } -> convertible_to<_Ref>;
+   { ranges::iter_move(__it) } -> convertible_to<_RRef>;
+  };
+
+template
+  concept __concat_indirectly_readable
+   = common_reference_with<__concat_reference_t<_Rs...>&&, 
__concat_value_t<_Rs...>&>
+ && common_reference_with<__concat_reference_t<_Rs...>&&,
+  __concat_rvalue_reference_t<_Rs...>&&>
+ && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
+  __concat_value_t<_Rs...> const&>
+ && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
+   
__concat_rvalue_reference_t<_Rs...>,
+   iterator_t<_Rs>>
+ && ...);
+
+template
+  concept __concatable = requires {
+   typename __concat_reference_t<_Rs...>;
+   typename __concat_value_t<_Rs...>;
+   typename __concat_rvalue_reference_t<_Rs...>;
+  } && __concat_indirectly_readable<_Rs...>;
+
+template
+  struct __all_but_last_common
+  {
+   static inline constexpr bool value
+ = requires { 

[PATCH] libstdc++: Implement ranges::concat_view from P2542R7

2024-04-22 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  More tests
are needed but I figured I'd submit this now for possible consideration into
GCC 14 since we're getting close to release..  All changes are confined to
C++26.

-- >8 --

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_concat): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__concat_reference_t): Define
for C++26.
(__detail::__concat_value_t): Likewise.
(__detail::__concat_rvalue_reference_t): Likewise.
(__detail::__concat_indirectly_readable_impl): Likewise.
(__detail::__concat_indirectly_readable): Likewise.
(__detail::__concatable): Likewise.
(__detail::__all_but_last_common): Likewise.
(__detail::__concat_is_random_access): Likewise.
(__detail::__concat_is_bidirectional): Likewise.
(__detail::__last_is_common): Likewise.
(concat_view): Likewise.
(__detail::__concat_view_iter_cat): Likewise.
(concat_view::iterator): Likewise.
(views::__detail::__can_concat_view): Likewise.
(views::_Concat, views::concat): Likewise.
* testsuite/std/ranges/concat/1.cc: New test.
---
 libstdc++-v3/include/bits/version.def |   8 +
 libstdc++-v3/include/bits/version.h   |  10 +
 libstdc++-v3/include/std/ranges   | 584 ++
 libstdc++-v3/testsuite/std/ranges/concat/1.cc |  61 ++
 4 files changed, 663 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/concat/1.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 5c0477fb61e..af13090c094 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1796,6 +1796,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_concat;
+  values = {
+v = 202403;
+cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 65e708c73fb..1f27bfe050d 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2003,4 +2003,14 @@
 #endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
 #undef __glibcxx_want_to_string
 
+#if !defined(__cpp_lib_ranges_concat)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_concat 202403L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
+#   define __cpp_lib_ranges_concat 202403L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_concat) && 
defined(__glibcxx_want_ranges_concat) */
+#undef __glibcxx_want_ranges_concat
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index afce818376b..28a39bf6f34 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -55,6 +55,7 @@
 #define __glibcxx_want_ranges_as_const
 #define __glibcxx_want_ranges_as_rvalue
 #define __glibcxx_want_ranges_cartesian_product
+#define __glibcxx_want_ranges_concat
 #define __glibcxx_want_ranges_chunk
 #define __glibcxx_want_ranges_chunk_by
 #define __glibcxx_want_ranges_enumerate
@@ -9514,6 +9515,589 @@ namespace __detail
 } // namespace ranges
 #endif // __cpp_lib_ranges_to_container
 
+#if __cpp_lib_ranges_concat // C++ >= C++26
+namespace ranges
+{
+  namespace __detail
+  {
+template
+  using __concat_reference_t = 
common_reference_t...>;
+
+template
+  using __concat_value_t = common_type_t...>;
+
+template
+  using __concat_rvalue_reference_t
+   = common_reference_t...>;
+
+template
+  concept __concat_indirectly_readable_impl = requires (const _It __it) {
+   { *__it } -> convertible_to<_Ref>;
+   { ranges::iter_move(__it) } -> convertible_to<_RRef>;
+  };
+
+template
+  concept __concat_indirectly_readable
+   = common_reference_with<__concat_reference_t<_Rs...>&&, 
__concat_value_t<_Rs...>&>
+ && common_reference_with<__concat_reference_t<_Rs...>&&,
+  __concat_rvalue_reference_t<_Rs...>&&>
+ && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
+  __concat_value_t<_Rs...> const&>
+ && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
+   
__concat_rvalue_reference_t<_Rs...>,
+   iterator_t<_Rs>>
+ && ...);
+
+template
+  concept __concatable = requires {
+   typename __concat_reference_t<_Rs...>;
+   typename __concat_value_t<_Rs...>;
+   typename __concat_rvalue_reference_t<_Rs...>;
+  } && __concat_indirectly_readable<_Rs...>;
+
+template
+  struct __all_but_last_common
+  {
+   static inline constexpr bool value
+ = requires { 

Re: [pushed] c++/modules: make bits_in/out move-constructible

2024-04-22 Thread Patrick Palka
On Mon, 22 Apr 2024, Christophe Lyon wrote:

> Hi Patrick,
> 
> On Sat, 13 Apr 2024 at 22:12, Patrick Palka  wrote:
> >
> > Pushed as obvious after verifying C++11 bootstrap is restored.
> 
> I guess this also fixes the bootstrap_ubsan breakage on aarch64
> reported by Linaro CI?
> See https://linaro.atlassian.net/browse/GNU-1199
> (I think you also received a notification about this a few days ago?)

Yes, sorry for the breakage.  r14-9955-g436ab7e8e8b broke bootstrap
due to relying on C++17 copy elision semantics, and this followup
patch trivially fixed that.

> 
> Thanks,
> 
> Christophe
> 
> >
> > -- >8 --
> >
> > gcc/cp/ChangeLog:
> >
> > * module.cc (struct bytes_in::bits_in): Define defaulted
> > move ctor.
> > (struct bytes_out::bits_out): Likewise.
> > ---
> >  gcc/cp/module.cc | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index bbed82652d4..c6f71e11515 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -706,6 +706,7 @@ struct bytes_in::bits_in {
> >  bflush ();
> >}
> >
> > +  bits_in(bits_in&&) = default;
> >bits_in(const bits_in&) = delete;
> >bits_in& operator=(const bits_in&) = delete;
> >
> > @@ -752,6 +753,7 @@ struct bytes_out::bits_out {
> >  bflush ();
> >}
> >
> > +  bits_out(bits_out&&) = default;
> >bits_out(const bits_out&) = delete;
> >bits_out& operator=(const bits_out&) = delete;
> >
> > --
> > 2.44.0.591.g8f7582d995
> >
> 
> 



Re: [PATCH] c++: Check if allocation functions are xobj members [PR114078]

2024-04-21 Thread Patrick Palka
On Sat, 20 Apr 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> A class allocation member function is implicitly 'static' by
> [class.free] p3, so cannot have an explicit object parameter.
> 
>   PR c++/114078
> 
> gcc/cp/ChangeLog:
> 
>   * decl.cc (grokdeclarator): Check allocation functions for xobj
>   parameters.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp23/explicit-obj-ops-alloc.C: New test.

LGTM

> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/decl.cc  |  6 ++
>  gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C | 11 +++
>  2 files changed, 17 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885ff..2af026d255d 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -13728,6 +13728,12 @@ grokdeclarator (const cp_declarator *declarator,
>   inform (DECL_SOURCE_LOCATION (xobj_parm),
>   "explicit object parameter declared here");
> }
> + if (unqualified_id
> + && identifier_p (unqualified_id)
> + && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
> +   error_at (DECL_SOURCE_LOCATION (xobj_parm),
> + "%qD cannot be an explicit object member "
> + "function", unqualified_id);
> }
> }
>   tree pushed_scope = NULL_TREE;
> diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C 
> b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
> new file mode 100644
> index 000..8a277db7ef5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
> @@ -0,0 +1,11 @@
> +// PR c++/114078
> +// { dg-do compile { target c++23 } }
> +
> +using size_t = decltype(sizeof(0));
> +
> +struct S {
> +  void* operator new(this size_t);  // { dg-error "explicit object" }
> +  void* operator new[](this size_t);  // { dg-error "explicit object" }
> +  void operator delete(this void*);  // { dg-error "explicit object" }
> +  void operator delete[](this void*);  // { dg-error "explicit object" }
> +};
> -- 
> 2.43.2
> 
> 



Re: [PATCH] c++: Fix ICE with xobj parms and maybe incomplete decl-specifiers

2024-04-21 Thread Patrick Palka
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> This fixes a null dereference issue when decl_specifiers.type is not yet
> provided.
> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_parameter_declaration): Check if
>   decl_specifiers.type is null.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp23/explicit-obj-basic7.C: New test.

LGTM

> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/parser.cc | 5 +++--
>  gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C | 9 +
>  2 files changed, 12 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 50d3ad35b61..97ee2650dc4 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -25780,8 +25780,9 @@ cp_parser_parameter_declaration (cp_parser *parser,
>  }
>  
>if (xobj_param_p
> -  && (declarator ? declarator->parameter_pack_p
> -  : PACK_EXPANSION_P (decl_specifiers.type)))
> +  && ((declarator && declarator->parameter_pack_p)
> +   || (decl_specifiers.type
> +   && PACK_EXPANSION_P (decl_specifiers.type
>  {
>location_t xobj_param
>   = make_location (decl_specifiers.locations[ds_this],
> diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C 
> b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
> new file mode 100644
> index 000..a474e97fc18
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
> @@ -0,0 +1,9 @@
> +// { dg-do compile { target c++23 } }
> +
> +// Shouldn't ICE
> +struct S {
> +  void a(this long);
> +  void b(this const long);
> +  void c(this long unsigned);
> +  void c(this signed);
> +};
> -- 
> 2.43.2
> 
> 



Re: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]

2024-04-18 Thread Patrick Palka
On Wed, 17 Apr 2024, Michael Levine (BLOOMBERG/ 919 3RD A) wrote:

> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including  
> when it should have been sufficient to only include .
> 
> When the patch is applied, the following code will compile: 
> https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k

Nice, thanks for the patch!

> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64

> From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
> From: Michael Levine 
> Date: Fri, 23 Feb 2024 14:13:13 -0500
> Subject: [PATCH 1/2] Fix the bug
> 
> Signed-off-by: Michael Levine 
> ---
>  libstdc++-v3/include/bits/ranges_algo.h | 52 --
>  libstdc++-v3/include/bits/stl_numeric.h | 57 -
>  2 files changed, 56 insertions(+), 53 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
> b/libstdc++-v3/include/bits/ranges_algo.h
> index 62faff173bd..d258be0b93f 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -3521,58 +3521,6 @@ namespace ranges
>  
>  #endif // __glibcxx_ranges_contains
>  
> -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> -
> -  template
> -struct out_value_result
> -{
> -  [[no_unique_address]] _Out out;
> -  [[no_unique_address]] _Tp value;
> -
> -  template
> - requires convertible_to
> -   && convertible_to
> - constexpr
> - operator out_value_result<_Out2, _Tp2>() const &
> - { return {out, value}; }
> -
> -  template
> - requires convertible_to<_Out, _Out2>
> -   && convertible_to<_Tp, _Tp2>
> - constexpr
> - operator out_value_result<_Out2, _Tp2>() &&
> - { return {std::move(out), std::move(value)}; }
> -};
> -
> -  template
> -using iota_result = out_value_result<_Out, _Tp>;
> -
> -  struct __iota_fn
> -  {
> -template _Sent, 
> weakly_incrementable _Tp>
> -  requires indirectly_writable<_Out, const _Tp&>
> -  constexpr iota_result<_Out, _Tp>
> -  operator()(_Out __first, _Sent __last, _Tp __value) const
> -  {
> - while (__first != __last)
> -   {
> - *__first = static_cast(__value);
> - ++__first;
> - ++__value;
> -   }
> - return {std::move(__first), std::move(__value)};
> -  }
> -
> -template _Range>
> -  constexpr iota_result, _Tp>
> -  operator()(_Range&& __r, _Tp __value) const
> -  { return (*this)(ranges::begin(__r), ranges::end(__r), 
> std::move(__value)); }
> -  };
> -
> -  inline constexpr __iota_fn iota{};
> -
> -#endif // __glibcxx_ranges_iota
> -
>  #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
>  
>struct __find_last_fn
> diff --git a/libstdc++-v3/include/bits/stl_numeric.h 
> b/libstdc++-v3/include/bits/stl_numeric.h
> index fe911154ab7..1b06c26dc02 100644
> --- a/libstdc++-v3/include/bits/stl_numeric.h
> +++ b/libstdc++-v3/include/bits/stl_numeric.h
> @@ -59,7 +59,7 @@
>  #include 
>  #include 
>  #include  // For _GLIBCXX_MOVE
> -
> +#include  // For _Range as used by std::ranges::iota
>  
>  namespace std _GLIBCXX_VISIBILITY(default)
>  {
> @@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  }
>  #endif
>  
> +namespace ranges
> +{
> +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> +
> +  template
> +struct out_value_result
> +{
> +  [[no_unique_address]] _Out out;
> +  [[no_unique_address]] _Tp value;
> +
> +  template
> + requires convertible_to
> +   && convertible_to
> + constexpr
> + operator out_value_result<_Out2, _Tp2>() const &
> + { return {out, value}; }
> +
> +  template
> + requires convertible_to<_Out, _Out2>
> +   && convertible_to<_Tp, _Tp2>
> + constexpr
> + operator out_value_result<_Out2, _Tp2>() &&
> + { return {std::move(out), std::move(value)}; }
> +};

IIUC out_value_result should continue to be available from , so we
probably don't want to move it to  (or one of its internal headers).
Better would be to move it to  I think.

> +
> +  template
> +using iota_result = out_value_result<_Out, _Tp>;
> +
> +  struct __iota_fn
> +  {
> +template _Sent, 
> weakly_incrementable _Tp>
> +  requires indirectly_writable<_Out, const _Tp&>
> +  constexpr iota_result<_Out, _Tp>
> +  operator()(_Out __first, _Sent __last, _Tp __value) const
> +  {
> + while (__first != __last)
> +   {
> + *__first = static_cast(__value);
> + ++__first;
> + ++__value;
> +  

Re: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]

2024-04-18 Thread Patrick Palka
On Wed, 17 Apr 2024, Michael Levine (BLOOMBERG/ 919 3RD A) wrote:

> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including  
> when it should have been sufficient to only include .
> 
> When the patch is applied, the following code will compile: 
> https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k

Nice, thanks for the patch!

> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64

> From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
> From: Michael Levine 
> Date: Fri, 23 Feb 2024 14:13:13 -0500
> Subject: [PATCH 1/2] Fix the bug
> 
> Signed-off-by: Michael Levine 
> ---
>  libstdc++-v3/include/bits/ranges_algo.h | 52 --
>  libstdc++-v3/include/bits/stl_numeric.h | 57 -
>  2 files changed, 56 insertions(+), 53 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
> b/libstdc++-v3/include/bits/ranges_algo.h
> index 62faff173bd..d258be0b93f 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -3521,58 +3521,6 @@ namespace ranges
>  
>  #endif // __glibcxx_ranges_contains
>  
> -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> -
> -  template
> -struct out_value_result
> -{
> -  [[no_unique_address]] _Out out;
> -  [[no_unique_address]] _Tp value;
> -
> -  template
> - requires convertible_to
> -   && convertible_to
> - constexpr
> - operator out_value_result<_Out2, _Tp2>() const &
> - { return {out, value}; }
> -
> -  template
> - requires convertible_to<_Out, _Out2>
> -   && convertible_to<_Tp, _Tp2>
> - constexpr
> - operator out_value_result<_Out2, _Tp2>() &&
> - { return {std::move(out), std::move(value)}; }
> -};
> -
> -  template
> -using iota_result = out_value_result<_Out, _Tp>;
> -
> -  struct __iota_fn
> -  {
> -template _Sent, 
> weakly_incrementable _Tp>
> -  requires indirectly_writable<_Out, const _Tp&>
> -  constexpr iota_result<_Out, _Tp>
> -  operator()(_Out __first, _Sent __last, _Tp __value) const
> -  {
> - while (__first != __last)
> -   {
> - *__first = static_cast(__value);
> - ++__first;
> - ++__value;
> -   }
> - return {std::move(__first), std::move(__value)};
> -  }
> -
> -template _Range>
> -  constexpr iota_result, _Tp>
> -  operator()(_Range&& __r, _Tp __value) const
> -  { return (*this)(ranges::begin(__r), ranges::end(__r), 
> std::move(__value)); }
> -  };
> -
> -  inline constexpr __iota_fn iota{};
> -
> -#endif // __glibcxx_ranges_iota
> -
>  #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
>  
>struct __find_last_fn
> diff --git a/libstdc++-v3/include/bits/stl_numeric.h 
> b/libstdc++-v3/include/bits/stl_numeric.h
> index fe911154ab7..1b06c26dc02 100644
> --- a/libstdc++-v3/include/bits/stl_numeric.h
> +++ b/libstdc++-v3/include/bits/stl_numeric.h
> @@ -59,7 +59,7 @@
>  #include 
>  #include 
>  #include  // For _GLIBCXX_MOVE
> -
> +#include  // For _Range as used by std::ranges::iota
>  
>  namespace std _GLIBCXX_VISIBILITY(default)
>  {
> @@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  }
>  #endif
>  
> +namespace ranges
> +{
> +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> +
> +  template
> +struct out_value_result
> +{
> +  [[no_unique_address]] _Out out;
> +  [[no_unique_address]] _Tp value;
> +
> +  template
> + requires convertible_to
> +   && convertible_to
> + constexpr
> + operator out_value_result<_Out2, _Tp2>() const &
> + { return {out, value}; }
> +
> +  template
> + requires convertible_to<_Out, _Out2>
> +   && convertible_to<_Tp, _Tp2>
> + constexpr
> + operator out_value_result<_Out2, _Tp2>() &&
> + { return {std::move(out), std::move(value)}; }
> +};

IIUC out_value_result should continue to be available from , so we
probably don't want to move it to  (or one of its internal headers).
Better would be to move it to  I think.

> +
> +  template
> +using iota_result = out_value_result<_Out, _Tp>;
> +
> +  struct __iota_fn
> +  {
> +template _Sent, 
> weakly_incrementable _Tp>
> +  requires indirectly_writable<_Out, const _Tp&>
> +  constexpr iota_result<_Out, _Tp>
> +  operator()(_Out __first, _Sent __last, _Tp __value) const
> +  {
> + while (__first != __last)
> +   {
> + *__first = static_cast(__value);
> + ++__first;
> + ++__value;
> +  

Re: [PATCH v2 2/2] c++/modules: Fix instantiation of imported temploid friends [PR114275]

2024-04-17 Thread Patrick Palka
On Mon, 15 Apr 2024, Nathaniel Shead wrote:

> I'm not a huge fan of always streaming 'imported_temploid_friends' for
> all decls, but I don't think it adds much performance cost over adding a
> new flag to categorise decls that might be marked as such.

IIUC this value is going to be almost always null which is encoded as a
single 0 byte, which should be fast to stream.  But I wonder how much
larger  gets?  Can we get away with streaming this value
only for TEMPLATE_DECLs?

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> This patch fixes a number of issues with the handling of temploid friend
> declarations.
> 
> The primary issue is that instantiations of friend declarations should
> attach the declaration to the same module as the befriending class, by
> [module.unit] p7.1 and [temp.friend] p2; this could be a different
> module from the current TU, and so needs special handling.

Nice, your approach seems consistent with Nathan's comments in the past
about this issue:

https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603288.html
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611215.htmlw

> 
> The other main issue here is that we can't assume that just because name
> lookup didn't find a definition for a hidden template class, it doesn't
> mean that it doesn't exist: it could be a non-exported entity that we've
> nevertheless streamed in from an imported module.  We need to ensure
> that when instantiating friend classes that we return the same TYPE_DECL
> that we got from our imports, otherwise we will get later issues with
> 'duplicate_decls' (rightfully) complaining that they're different.
> 
> This doesn't appear necessary for functions due to the existing name
> lookup handling already finding these hidden declarations.

It does seem like a weird inconsistency that tsubst_friend_class needs
this workaround but not tsubst_friend_function.

I wonder if we can relax duplicate_decls to treat an instantiated
template friend class as a redeclaration instead of complaining,
mirroring its behavior for functions, which in turn would let us get rid
of the name lookup in tsubst_friend_class and eliminate the need for
lookup_imported_hidden_friend?  This may be too speculative/risky of
a refactoring at this stage though, and your approach has the nice
advantage of changing only modules code paths.

In any case I hope we can fix this issue for GCC 14!  LGTM overall.

> 
>   PR c++/105320
>   PR c++/114275
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (propagate_defining_module): Declare.
>   (lookup_imported_hidden_friend): Declare.
>   * decl.cc (duplicate_decls): Also check if hidden declarations
>   can be redeclared in this module.
>   * module.cc (imported_temploid_friends): New map.
>   (init_modules): Initialize it.
>   (trees_out::decl_value): Write it.
>   (trees_in::decl_value): Read it.
>   (get_originating_module_decl): Follow the owning decl for an
>   imported temploid friend.
>   (propagate_defining_module): New function.
>   * name-lookup.cc (lookup_imported_hidden_friend): New function.
>   * pt.cc (tsubst_friend_function): Propagate defining module for
>   new friend functions.
>   (tsubst_friend_class): Lookup imported hidden friends. Check
>   for valid redeclaration. Propagate defining module for new
>   friend classes.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/tpl-friend-10_a.C: New test.
>   * g++.dg/modules/tpl-friend-10_b.C: New test.
>   * g++.dg/modules/tpl-friend-10_c.C: New test.
>   * g++.dg/modules/tpl-friend-11_a.C: New test.
>   * g++.dg/modules/tpl-friend-11_b.C: New test.
>   * g++.dg/modules/tpl-friend-12_a.C: New test.
>   * g++.dg/modules/tpl-friend-12_b.C: New test.
>   * g++.dg/modules/tpl-friend-12_c.C: New test.
>   * g++.dg/modules/tpl-friend-12_d.C: New test.
>   * g++.dg/modules/tpl-friend-12_e.C: New test.
>   * g++.dg/modules/tpl-friend-12_f.C: New test.
>   * g++.dg/modules/tpl-friend-13_a.C: New test.
>   * g++.dg/modules/tpl-friend-13_b.C: New test.
>   * g++.dg/modules/tpl-friend-13_c.C: New test.
>   * g++.dg/modules/tpl-friend-13_d.C: New test.
>   * g++.dg/modules/tpl-friend-13_e.C: New test.
>   * g++.dg/modules/tpl-friend-9.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/cp-tree.h  |  2 +
>  gcc/cp/decl.cc| 36 +++--
>  gcc/cp/module.cc  | 52 +++
>  gcc/cp/name-lookup.cc | 42 +++
>  gcc/cp/pt.cc  | 19 +++
>  .../g++.dg/modules/tpl-friend-10_a.C  | 15 ++
>  .../g++.dg/modules/tpl-friend-10_b.C  |  5 ++
>  .../g++.dg/modules/tpl-friend-10_c.C  |  7 +++
>  .../g++.dg/modules/tpl-friend-11_a.C  | 14 +
>  

Re: [PATCH v2 1/2] c++: Standardise errors for module_may_redeclare

2024-04-17 Thread Patrick Palka
On Mon, 15 Apr 2024, Nathaniel Shead wrote:

> I took another look at this patch and have split it into two, one (this
> one) to standardise the error messages used and prepare
> 'module_may_redeclare' for use with temploid friends, and another
> followup patch to actually handle them correctly.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

LGTM

> 
> -- >8 --
> 
> Currently different places calling 'module_may_redeclare' all emit very
> similar but slightly different error messages, and handle different
> kinds of declarations differently.  This patch makes the function
> perform its own error messages so that they're all in one place, and
> prepares it for use with temploid friends (PR c++/114275).
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (module_may_redeclare): Add default parameter.
>   * decl.cc (duplicate_decls): Don't emit errors for failed
>   module_may_redeclare.
>   (xref_tag): Likewise.
>   (start_enum): Likewise.
>   * semantics.cc (begin_class_definition): Likewise.
>   * module.cc (module_may_redeclare): Clean up logic. Emit error
>   messages on failure.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/enum-12.C: Update error message.
>   * g++.dg/modules/friend-5_b.C: Likewise.
>   * g++.dg/modules/shadow-1_b.C: Likewise.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/cp-tree.h  |   2 +-
>  gcc/cp/decl.cc|  28 +
>  gcc/cp/module.cc  | 120 ++
>  gcc/cp/semantics.cc   |   6 +-
>  gcc/testsuite/g++.dg/modules/enum-12.C|   2 +-
>  gcc/testsuite/g++.dg/modules/friend-5_b.C |   2 +-
>  gcc/testsuite/g++.dg/modules/shadow-1_b.C |   5 +-
>  7 files changed, 89 insertions(+), 76 deletions(-)
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 1dbb577a38d..faa7a0052a5 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7401,7 +7401,7 @@ inline bool module_exporting_p ()
>  
>  extern module_state *get_module (tree name, module_state *parent = NULL,
>bool partition = false);
> -extern bool module_may_redeclare (tree decl);
> +extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL);
>  
>  extern bool module_global_init_needed ();
>  extern bool module_determine_import_inits ();
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885ff..aa66da4829d 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> hiding, bool was_hidden)
>&& TREE_CODE (olddecl) != NAMESPACE_DECL
>&& !hiding)
>  {
> -  if (!module_may_redeclare (olddecl))
> - {
> -   if (DECL_ARTIFICIAL (olddecl))
> - error ("declaration %qD conflicts with builtin", newdecl);
> -   else
> - {
> -   error ("declaration %qD conflicts with import", newdecl);
> -   inform (olddecl_loc, "import declared %q#D here", olddecl);
> - }
> -
> -   return error_mark_node;
> - }
> +  if (!module_may_redeclare (olddecl, newdecl))
> + return error_mark_node;
>  
>tree not_tmpl = STRIP_TEMPLATE (olddecl);
>if (DECL_LANG_SPECIFIC (not_tmpl)
> @@ -16620,12 +16610,7 @@ xref_tag (enum tag_types tag_code, tree name,
>   {
> tree decl = TYPE_NAME (t);
> if (!module_may_redeclare (decl))
> - {
> -   auto_diagnostic_group d;
> -   error ("cannot declare %qD in a different module", decl);
> -   inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
> -   return error_mark_node;
> - }
> + return error_mark_node;
>  
> tree not_tmpl = STRIP_TEMPLATE (decl);
> if (DECL_LANG_SPECIFIC (not_tmpl)
> @@ -16973,12 +16958,7 @@ start_enum (tree name, tree enumtype, tree 
> underlying_type,
>   {
> tree decl = TYPE_NAME (enumtype);
> if (!module_may_redeclare (decl))
> - {
> -   auto_diagnostic_group d;
> -   error ("cannot declare %qD in different module", decl);
> -   inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
> -   enumtype = error_mark_node;
> - }
> + enumtype = error_mark_node;
> else
>   set_instantiating_module (decl);
>   }
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 001430a4a8f..e2d2910ae48 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -18992,11 +18992,15 @@ get_importing_module (tree decl, bool flexible)
>return module->mod;
>  }
>  
> -/* Is it permissible to redeclare DECL.  */
> +/* Is it permissible to redeclare OLDDECL with NEWDECL.
> +
> +   If NEWDECL is NULL, assumes that OLDDECL will be redeclared using
> +   the current scope's module and attachment.  */
>  
>  bool
> -module_may_redeclare (tree decl)
> +module_may_redeclare (tree olddecl, tree newdecl)
>  

[gcc r13-8608] c++: requires-exprs and partial constraint subst [PR110006]

2024-04-15 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:38c2679ff9330d3ac1d5d86459294446733a435a

commit r13-8608-g38c2679ff9330d3ac1d5d86459294446733a435a
Author: Patrick Palka 
Date:   Fri Feb 2 19:07:08 2024 -0500

c++: requires-exprs and partial constraint subst [PR110006]

In r11-3261-gb28b621ac67bee we made tsubst_requires_expr never partially
substitute into a requires-expression so as to avoid checking its
requirements out of order during e.g. generic lambda regeneration.

These PRs however illustrate that we still sometimes do need to
partially substitute into a requires-expression, in particular when it
appears in associated constraints that we're directly substituting for
sake of declaration matching or dguide constraint rewriting.  In these
cases we're being called from tsubst_constraint during which
processing_constraint_expression_p is true, so this patch checks this
predicate to control whether we defer substitution or partially
substitute.

In turn, we now need to propagate semantic tsubst flags through
tsubst_requires_expr rather than just using tf_none, notably for sake of
dguide constraint rewriting which sets tf_dguide.

PR c++/110006
PR c++/112769

gcc/cp/ChangeLog:

* constraint.cc (subst_info::quiet): Accomodate non-diagnostic
tsubst flags.
(tsubst_valid_expression_requirement): Likewise.
(tsubst_simple_requirement): Return a substituted _REQ node when
processing_template_decl.
(tsubst_type_requirement_1): Accomodate non-diagnostic tsubst
flags.
(tsubst_type_requirement): Return a substituted _REQ node when
processing_template_decl.
(tsubst_compound_requirement): Likewise.  Accomodate non-diagnostic
tsubst flags.
(tsubst_nested_requirement): Likewise.
(tsubst_requires_expr): Don't defer partial substitution when
processing_constraint_expression_p is true, in which case return
a substituted REQUIRES_EXPR.
* pt.cc (tsubst_expr) : Accomodate
non-diagnostic tsubst flags.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-alias18.C: New test.
* g++.dg/cpp2a/concepts-friend16.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 686b5eb9c9ee623a604dde5c49fa11c23f384c62)

Diff:
---
 gcc/cp/constraint.cc   | 56 +-
 gcc/cp/pt.cc   |  3 +-
 .../g++.dg/cpp2a/class-deduction-alias18.C | 13 +
 gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C | 25 ++
 4 files changed, 84 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 273d15ab097..971619eabea 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -85,7 +85,7 @@ struct subst_info
   /* True if we should not diagnose errors.  */
   bool quiet() const
   {
-return complain == tf_none;
+return !(complain & tf_warning_or_error);
   }
 
   /* True if we should diagnose errors.  */
@@ -1999,8 +1999,9 @@ hash_placeholder_constraint (tree c)
 static tree
 tsubst_valid_expression_requirement (tree t, tree args, sat_info info)
 {
-  tree r = tsubst_expr (t, args, tf_none, info.in_decl);
-  if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node)
+  tsubst_flags_t quiet = info.complain & ~tf_warning_or_error;
+  tree r = tsubst_expr (t, args, quiet, info.in_decl);
+  if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node)
 return r;
 
   if (info.diagnose_unsatisfaction_p ())
@@ -2036,6 +2037,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info 
info)
   tree expr = tsubst_valid_expression_requirement (t0, args, info);
   if (expr == error_mark_node)
 return error_mark_node;
+  if (processing_template_decl)
+return finish_simple_requirement (EXPR_LOCATION (t), expr);
   return boolean_true_node;
 }
 
@@ -2045,7 +2048,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info 
info)
 static tree
 tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc)
 {
-  tree r = tsubst (t, args, tf_none, info.in_decl);
+  tsubst_flags_t quiet = info.complain & ~tf_warning_or_error;
+  tree r = tsubst (t, args, quiet, info.in_decl);
   if (r != error_mark_node)
 return r;
 
@@ -2076,6 +2080,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info)
   tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t));
   if (type == error_mark_node)
 return error_mark_node;
+  if (processing_template_decl)
+return finish_type_requirement (EXPR_LOCATION (t), type);
   return boolean_true_node;
 }
 
@@ -2132,9 +2138,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info 
info)
 
   location_t loc = cp_expr_loc_or_input_loc (expr);
 
+  subst_info quiet (i

[pushed] c++/modules: make bits_in/out move-constructible

2024-04-13 Thread Patrick Palka
Pushed as obvious after verifying C++11 bootstrap is restored.

-- >8 --

gcc/cp/ChangeLog:

* module.cc (struct bytes_in::bits_in): Define defaulted
move ctor.
(struct bytes_out::bits_out): Likewise.
---
 gcc/cp/module.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index bbed82652d4..c6f71e11515 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -706,6 +706,7 @@ struct bytes_in::bits_in {
 bflush ();
   }
 
+  bits_in(bits_in&&) = default;
   bits_in(const bits_in&) = delete;
   bits_in& operator=(const bits_in&) = delete;
 
@@ -752,6 +753,7 @@ struct bytes_out::bits_out {
 bflush ();
   }
 
+  bits_out(bits_out&&) = default;
   bits_out(const bits_out&) = delete;
   bits_out& operator=(const bits_out&) = delete;
 
-- 
2.44.0.591.g8f7582d995



[gcc r14-9956] c++/modules: make bits_in/out move-constructible

2024-04-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:da375baf54944298303f13c375a5756c6131d672

commit r14-9956-gda375baf54944298303f13c375a5756c6131d672
Author: Patrick Palka 
Date:   Sat Apr 13 16:06:28 2024 -0400

c++/modules: make bits_in/out move-constructible

gcc/cp/ChangeLog:

* module.cc (struct bytes_in::bits_in): Define defaulted
move ctor.
(struct bytes_out::bits_out): Likewise.

Diff:
---
 gcc/cp/module.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index bbed82652d4..c6f71e11515 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -706,6 +706,7 @@ struct bytes_in::bits_in {
 bflush ();
   }
 
+  bits_in(bits_in&&) = default;
   bits_in(const bits_in&) = delete;
   bits_in& operator=(const bits_in&) = delete;
 
@@ -752,6 +753,7 @@ struct bytes_out::bits_out {
 bflush ();
   }
 
+  bits_out(bits_out&&) = default;
   bits_out(const bits_out&) = delete;
   bits_out& operator=(const bits_out&) = delete;


Re: [PATCH] c++/modules: optimize tree flag streaming

2024-04-13 Thread Patrick Palka
On Sat, 13 Apr 2024, Iain Sandoe wrote:

> Hi Patrick,
> 
> > On 10 Apr 2024, at 17:33, Jason Merrill  wrote:
> > 
> > On 4/10/24 11:26, Patrick Palka wrote:
> >> On Wed, 10 Apr 2024, Patrick Palka wrote:
> >>> 
> >>> On Tue, 9 Apr 2024, Jason Merrill wrote:
> >>> 
> >>>> On 2/16/24 10:06, Patrick Palka wrote:
> >>>>> On Thu, 15 Feb 2024, Patrick Palka wrote:
> >>>>> 
> 
> 
> 
> > Let's keep documenting the inheritance relationship here, i.e.
> > 
> >  bytes_in : data
> > 
> >> @@ -694,13 +656,132 @@ protected:
> >>/* Instrumentation.  */
> >>static unsigned spans[4];
> >>static unsigned lengths[4];
> >> -  static int is_set;
> >> +  friend struct bits_out;
> > 
> > It might be a little more elegant for bits_in/out to be nested classes of 
> > bytes_in/out, returned from member functions, rather than friends 
> > constructed directly?  OK either way, with the above comment tweak.
> 
> Unfortunately, this seems to break x86_64 Darwin bootstrap with fails as 
> below - I did not yet have a chance to look in any morre detail, so this is a 
> head’s up - unless you have any immediate ideas?
> 
> thanks
> Iain
> 
> 
> /src-local/gcc-master/gcc/cp/module.cc: In member function 
> ‘{anonymous}::bytes_in::bits_in {anonymous}::bytes_in::stream_bits()’:
> /src-local/gcc-master/gcc/cp/module.cc:735:24: error: use of deleted function 
> ‘{anonymous}::bytes_in::bits_in::bits_in(const 
> {anonymous}::bytes_in::bits_in&)’
>   735 |   return bits_in (*this);
>   |^
> /src-local/gcc-master/gcc/cp/module.cc:709:3: note: declared here
>   709 |   bits_in(const bits_in&) = delete;
>   |   ^~~
> /src-local/gcc-master/gcc/cp/module.cc: In member function 
> ‘{anonymous}::bytes_out::bits_out {anonymous}::bytes_out::stream_bits()’:
> /src-local/gcc-master/gcc/cp/module.cc:796:25: error: use of deleted function 
> ‘{anonymous}::bytes_out::bits_out::bits_out(const 
> {anonymous}::bytes_out::bits_out&)’
>   796 |   return bits_out (*this);
>   | ^
> /src-local/gcc-master/gcc/cp/module.cc:755:3: note: declared here
>   755 |   bits_out(const bits_out&) = delete;
>   |   ^~~~

Drat, sorry for the breakage.  We need to define defaulted move ctors
for these classes I think.  I'll take care of it ASAP.

[gcc r14-9955] c++/modules: optimize tree flag streaming

2024-04-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:436ab7e8e8b16866d8a807af242560ad4fdff0d6

commit r14-9955-g436ab7e8e8b16866d8a807af242560ad4fdff0d6
Author: Patrick Palka 
Date:   Sat Apr 13 10:52:32 2024 -0400

c++/modules: optimize tree flag streaming

One would expect consecutive calls to bytes_in/out::b for streaming
adjacent bits, as is done for tree flag streaming, to at least be
optimized by the compiler into individual bit operations using
statically known bit positions (and ideally combined into larger sized
reads/writes).

Unfortunately this doesn't happen because the compiler has trouble
tracking the values of this->bit_pos and this->bit_val across the
calls, likely because the compiler doesn't know the value of 'this'.
Thus for each consecutive bit stream operation, bit_pos and bit_val are
loaded from 'this', checked if buffering is needed, and finally the bit
is extracted from bit_val according to the (unknown) bit_pos, even
though relative to the previous operation (if we didn't need to buffer)
bit_val is unchanged and bit_pos is just 1 larger.  This ends up being
quite slow, with tree_node_bools taking 10% of time when streaming in
the std module.

This patch improves this by making tracking of bit_pos and bit_val
easier for the compiler.  Rather than bit_pos and bit_val being members
of the (effectively global) bytes_in/out objects, this patch factors out
the bit streaming code/state into separate classes bits_in/out that get
constructed locally as needed for bit streaming.  Since these objects
are now clearly local, the compiler can more easily track their values
and optimize away redundant buffering checks.

And since bit streaming is intended to be batched it's natural for these
new classes to be RAII-enabled such that the bit stream is flushed upon
destruction.

In order to make the most of this improved tracking of bit position,
this patch changes parts where we conditionally stream a tree flag
to unconditionally stream (the flag or a dummy value).  That way
the number of bits streamed and the respective bit positions are as
statically known as reasonably possible.  In lang_decl_bools and
lang_type_bools this patch makes us flush the current bit buffer at the
start so that subsequent bit positions are in turn statically known.
And in core_bools, we can add explicit early exits utilizing invariants
that the compiler can't figure out itself (e.g. a tree code can't have
both TS_TYPE_COMMON and TS_DECL_COMMON, and if a tree code doesn't have
TS_DECL_COMMON then it doesn't have TS_DECL_WITH_VIS).

This patch also moves the definitions of the relevant streaming classes
into anonymous namespaces so that the compiler can make more informed
decisions about inlining their member functions.

After this patch, compile time for a simple Hello World using the std
module is reduced by 7% with a release compiler.  The on-disk size of
the std module increases by 0.4% (presumably due to the extra flushing
done in lang_decl_bools and lang_type_bools).

The bit stream out performance isn't improved as much as the stream in
due to the spans/lengths instrumentation performed on stream out (which
maybe should be disabled for release builds?)

gcc/cp/ChangeLog:

* module.cc: Update comment about classes defined within.
(class data): Enclose in an anonymous namespace.
(data::calc_crc): Moved from bytes::calc_crc.
(class bytes): Remove.  Move bit_flush to namespace scope.
(class bytes_in): Enclose in an anonymous namespace.  Inherit
directly from data and adjust accordingly.  Move b and bflush
members to bits_in.
(class bytes_out): As above.  Remove is_set static data member.
(bit_flush): Moved from class bytes.
(struct bytes_in::bits_in): Define.
(struct bytes_out::bits_out): Define.
(bytes_in::stream_bits): Define.
(bytes_out::stream_bits): Define.
(bytes_out::bflush): Moved to bits_out/in.
(bytes_in::bflush): Likewise
(bytes_in::bfill): Removed.
(bytes_out::b): Moved to bits_out/in.
(bytes_in::b): Likewise.
(class trees_in): Enclose in an anonymous namespace.
(class trees_out): Enclose in an anonymous namespace.
(trees_out::core_bools): Add bits_out/in parameter and use it.
Unconditionally stream a bit for public_flag.  Add early exits
as appropriate.
(trees_out::core_bools): Likewise.
(trees_out::lang_decl_bools): Add bits_out/in parameter and use
it.  Flush the current bit buffer at the start.  Unconditionally
stream a bit for module_keyed_decls_p.
(trees_in::lang_decl

  1   2   3   4   5   6   7   8   9   10   >