[gcc r15-3145] c++: Add testcase for (now fixed) regression [PR113746]

2024-08-24 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:1d09ccc4a5fe7c9a3dd37fcef34c1523a5c95819

commit r15-3145-g1d09ccc4a5fe7c9a3dd37fcef34c1523a5c95819
Author: Simon Martin 
Date:   Fri Aug 23 10:49:31 2024 +0200

c++: Add testcase for (now fixed) regression [PR113746]

The case in PR113746 used to ICE until commit r15-123-gf04dc89a991ddc.
This patch simply adds the case to the testsuite.

PR c++/113746

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash76.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/parse/crash76.C | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/gcc/testsuite/g++.dg/parse/crash76.C 
b/gcc/testsuite/g++.dg/parse/crash76.C
new file mode 100644
index ..6fbd1fa9f7eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash76.C
@@ -0,0 +1,6 @@
+// PR c++/113746
+// { dg-do compile }
+
+template struct S { // { dg-error "not been declared" }
+  enum { e0 = 0, e00 = e0 };
+};


[gcc r15-3195] c++: Check template parameters in member class template specialization [PR115716]

2024-08-26 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:26ee954476bef7328d2cf45928c3c9b84df77178

commit r15-3195-g26ee954476bef7328d2cf45928c3c9b84df77178
Author: Simon Martin 
Date:   Sun Aug 25 21:59:31 2024 +0200

c++: Check template parameters in member class template specialization 
[PR115716]

We currently ICE upon the following invalid code, because we don't check
that the template parameters in a member class template specialization
are correct.

=== cut here ===
template  struct x {
  template  struct y {
typedef T result2;
  };
};
template<> template struct x::y {
  typedef double result2;
};
int main() {
  x::y::result2 xxx2;
}
=== cut here ===

This patch fixes the PR by calling redeclare_class_template.

PR c++/115716

gcc/cp/ChangeLog:

* pt.cc (maybe_process_partial_specialization): Call
redeclare_class_template.

gcc/testsuite/ChangeLog:

* g++.dg/template/spec42.C: New test.
* g++.dg/template/spec43.C: New test.

Diff:
---
 gcc/cp/pt.cc   |  5 +
 gcc/testsuite/g++.dg/template/spec42.C | 17 +
 gcc/testsuite/g++.dg/template/spec43.C | 18 ++
 3 files changed, 40 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bc3ad5edcc59..24a6241d3a51 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1173,6 +1173,11 @@ maybe_process_partial_specialization (tree type)
   type, inst);
}
 
+ /* Make sure that the specialization is valid.  */
+ if (!redeclare_class_template (type, current_template_parms,
+current_template_constraints ()))
+   return error_mark_node;
+
  /* Mark TYPE as a specialization.  And as a result, we only
 have one level of template argument for the innermost
 class template.  */
diff --git a/gcc/testsuite/g++.dg/template/spec42.C 
b/gcc/testsuite/g++.dg/template/spec42.C
new file mode 100644
index ..cac1264fc9f2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec42.C
@@ -0,0 +1,17 @@
+// PR c++/115716
+// { dg-do compile }
+template  struct x {
+  template  struct y { // { dg-note "used 1 template parameter" }
+typedef T result2;
+  };
+};
+
+template<>
+template
+struct x::y { // { dg-error "redeclared with 2 template parameters" }
+  typedef double result2;
+};
+
+int main() {
+  x::y::result2 xxx2;
+}
diff --git a/gcc/testsuite/g++.dg/template/spec43.C 
b/gcc/testsuite/g++.dg/template/spec43.C
new file mode 100644
index ..d33659dd5063
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec43.C
@@ -0,0 +1,18 @@
+// PR c++/115716
+// { dg-do compile { target c++20 } }
+template  struct x {
+  template  struct y { // { dg-note "original" }
+typedef T result2;
+  };
+};
+
+template<>
+template
+requires true
+struct x::y { // { dg-error "different constraints" }
+  typedef double result2;
+};
+
+int main() {
+  x::y::result2 xxx2;
+}


[gcc r15-3232] c++: Don't show constructor internal name in error message [PR105483]

2024-08-27 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:02dff52c60e5b89d290147f142f655c7817154c2

commit r15-3232-g02dff52c60e5b89d290147f142f655c7817154c2
Author: Simon Martin 
Date:   Mon Aug 26 14:09:46 2024 +0200

c++: Don't show constructor internal name in error message [PR105483]

We mention 'X::__ct' instead of 'X::X' in the "names the constructor,
not the type" error for this invalid code:

=== cut here ===
struct X {};
void g () {
  X::X x;
}
=== cut here ===

The problem is that we use %<%T::%D%> to build the error message, while
%qE does exactly what we need since we have DECL_CONSTRUCTOR_P. This is
what this patch does.

It also skips until the end of the statement and returns error_mark_node
for this and the preceding if block, to avoid emitting extra (useless)
errors.

PR c++/105483

gcc/cp/ChangeLog:

* parser.cc (cp_parser_expression_statement): Use %qE instead of
incorrect %<%T::%D%>. Skip to end of statement and return
error_mark_node in case of error.

gcc/testsuite/ChangeLog:

* g++.dg/parse/error36.C: Adjust test expectation.
* g++.dg/tc1/dr147.C: Likewise.
* g++.old-deja/g++.other/typename1.C: Likewise.
* g++.dg/diagnostic/pr105483.C: New test.

Diff:
---
 gcc/cp/parser.cc | 14 +-
 gcc/testsuite/g++.dg/diagnostic/pr105483.C   |  7 +++
 gcc/testsuite/g++.dg/parse/error36.C |  4 ++--
 gcc/testsuite/g++.dg/tc1/dr147.C |  2 +-
 gcc/testsuite/g++.old-deja/g++.other/typename1.C |  2 +-
 5 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 28ebf2beb60a..a722641be347 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -13232,18 +13232,22 @@ cp_parser_expression_statement (cp_parser* parser, 
tree in_statement_expr)
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
   && !cp_parser_uncommitted_to_tentative_parse_p (parser))
 {
+  bool has_errored = true;
   if (TREE_CODE (statement) == SCOPE_REF)
error_at (token->location, "need % before %qE because "
  "%qT is a dependent scope",
  statement, TREE_OPERAND (statement, 0));
   else if (is_overloaded_fn (statement)
   && DECL_CONSTRUCTOR_P (get_first_fn (statement)))
+   /* A::A a; */
+   error_at (token->location, "%qE names the constructor, not the type",
+ get_first_fn (statement));
+  else
+   has_errored = false;
+  if (has_errored)
{
- /* A::A a; */
- tree fn = get_first_fn (statement);
- error_at (token->location,
-   "%<%T::%D%> names the constructor, not the type",
-   DECL_CONTEXT (fn), DECL_NAME (fn));
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
}
 }
 
diff --git a/gcc/testsuite/g++.dg/diagnostic/pr105483.C 
b/gcc/testsuite/g++.dg/diagnostic/pr105483.C
new file mode 100644
index ..b935bacea11b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/pr105483.C
@@ -0,0 +1,7 @@
+// PR c++/105483
+// { dg-do compile }
+
+struct X { };
+void g () {
+  X::X x; // { dg-error "'X::X' names the constructor" }
+}
diff --git a/gcc/testsuite/g++.dg/parse/error36.C 
b/gcc/testsuite/g++.dg/parse/error36.C
index bf57a6b68ce8..73b550e3f2ad 100644
--- a/gcc/testsuite/g++.dg/parse/error36.C
+++ b/gcc/testsuite/g++.dg/parse/error36.C
@@ -12,7 +12,7 @@ void f(T t)
 {
   typedef A::foo type;  // { dg-error "typename" }
   A::bar b; // { dg-error "typename" "typename" }
-} // { dg-error "expected ';'" "expected" { target *-*-* } .-1 }
+}
 
 // PR c++/36353
 template  struct B
@@ -20,7 +20,7 @@ template  struct B
   void f()
   {
 A::baz z;   // { dg-error "typename" "typename" }
-  } // { dg-error "expected ';'" "expected" { target *-*-* } .-1 }
+  }
 };
 
 // PR c++/40738
diff --git a/gcc/testsuite/g++.dg/tc1/dr147.C b/gcc/testsuite/g++.dg/tc1/dr147.C
index 6b656491e816..ced18d1879cc 100644
--- a/gcc/testsuite/g++.dg/tc1/dr147.C
+++ b/gcc/testsuite/g++.dg/tc1/dr147.C
@@ -21,7 +21,7 @@ void A::f()
 void f()
 {
   A::A a; // { dg-error "constructor" "constructor" }
-} // { dg-error "" "error cascade" { target *-*-* } .-1 } error cascade
+}
 }
 
 namespace N2 {
diff --git a/gcc/testsuite/g++.old-deja/g++.other/typename1.C 
b/gcc/testsuite/g++.old-deja/g++.other/typename1.C
index 4e1a4a834ddd..0f0f68b1cee2 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/typename1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/typename1.C
@@ -14,4 +14,4 @@ template
 void f()
 {
   Vector::iterator i = 0; // { dg-error "typename" "typename" } missing 
typename
-} // { dg-error "expected" "expected" { target *-*-* } .-1 }
+}


[gcc r15-3598] c++: Don't ICE to build private access error message [PR116323]

2024-09-12 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:19831baf4904d09a74c7cf684a27b091947a610b

commit r15-3598-g19831baf4904d09a74c7cf684a27b091947a610b
Author: Simon Martin 
Date:   Tue Sep 10 22:33:18 2024 +0200

c++: Don't ICE to build private access error message [PR116323]

We currently ICE upon the following code while building the "[...] is
private within this context" error message

=== cut here ===
class A { enum Enum{}; };
template class Alloc>
class B : private Alloc, private A {};
template class Alloc>
int B::foo (Enum m) { return 42; }
=== cut here ===

The problem is that since r11-6880, after detecting that Enum cannot be
accessed in B, enforce_access will access the TYPE_BINFO of all the
bases of B, which ICEs for any that is a BOUND_TEMPLATE_TEMPLATE_PARM.
This patch simply skips such bases.

PR c++/116323

gcc/cp/ChangeLog:

* search.cc (get_parent_with_private_access): Only call 
access_in_type
for RECORD_OR_UNION_TYPE_P base BINFOs.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/search.cc |  8 ++--
 gcc/testsuite/g++.dg/template/access43.C | 11 +++
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index 60c30ecb8818..6a21a25272b2 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -160,12 +160,16 @@ get_parent_with_private_access (tree decl, tree binfo)
 
   tree base_binfo = NULL_TREE;
 
-  /* Iterate through immediate parent classes.  */
+  /* Iterate through immediate parent classes.
+ Note that the base list might contain WILDCARD_TYPE_P types, that
+ should be ignored here.  */
   for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
 {
+  tree base_binfo_type = BINFO_TYPE (base_binfo);
   /* This parent had private access.  Therefore that's why BINFO can't
  access DECL.  */
-  if (access_in_type (BINFO_TYPE (base_binfo), decl) == ak_private)
+  if (RECORD_OR_UNION_TYPE_P (base_binfo_type)
+ && access_in_type (base_binfo_type, decl) == ak_private)
return base_binfo;
 }
 
diff --git a/gcc/testsuite/g++.dg/template/access43.C 
b/gcc/testsuite/g++.dg/template/access43.C
new file mode 100644
index ..ce9e6c8fbb25
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access43.C
@@ -0,0 +1,11 @@
+// PR c++/116323
+// { dg-do "compile" }
+// { dg-additional-options "-Wno-template-body" }
+
+class A { enum Enum{}; };
+
+template class Alloc>
+class B : private Alloc, private A {};
+
+template class Alloc>
+int B::foo (Enum m) { return 42; } // { dg-error "is private" }


[gcc r15-3642] c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP [PR116681]

2024-09-14 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:005f7176e0f457a1e1a7398ddcb4a4972da28c62

commit r15-3642-g005f7176e0f457a1e1a7398ddcb4a4972da28c62
Author: Simon Martin 
Date:   Fri Sep 13 16:40:22 2024 +0200

c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP 
[PR116681]

We currently ICE upon the following testcase when using -ftime-report

=== cut here ===
template < int> using __conditional_t = int;
template < typename _Iter >
concept random_access_iterator = requires { new _Iter; };
template < typename _Iterator >
struct reverse_iterator {
  using iterator_concept =
__conditional_t< random_access_iterator< _Iterator>>;
};
void RemoveBottom() {
  int iter;
  for (reverse_iterator< int > iter;;)
  ;
}
=== cut here ===

The problem is that qualified_namespace_lookup does a plain start() of
the TV_NAME_LOOKUP timer (that asserts that the timer is not already
started). However this timer has already been cond_start()'d in the call
stack - by pushdecl - so the assert fails.

This patch simply ensures that we always conditionally start this timer
(which is done in all other places that use it).

PR c++/116681

gcc/cp/ChangeLog:

* name-lookup.cc (qualified_namespace_lookup): Use an
auto_cond_timer instead of using timevar_start and timevar_stop.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-pr116681.C: New test.

Diff:
---
 gcc/cp/name-lookup.cc  |  3 +--
 gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C | 20 
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index bfe17b7cb2fc..c7a693e02d59 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -7421,10 +7421,9 @@ tree lookup_qualified_name (tree t, const char *p, 
LOOK_want w, bool c)
 static bool
 qualified_namespace_lookup (tree scope, name_lookup *lookup)
 {
-  timevar_start (TV_NAME_LOOKUP);
+  auto_cond_timevar tv (TV_NAME_LOOKUP);
   query_oracle (lookup->name);
   bool found = lookup->search_qualified (ORIGINAL_NAMESPACE (scope));
-  timevar_stop (TV_NAME_LOOKUP);
   return found;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C
new file mode 100644
index ..f1b47797f1ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C
@@ -0,0 +1,20 @@
+// PR c++/116681
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-ftime-report" }
+// { dg-allow-blank-lines-in-output 1 }
+// { dg-prune-output "Time variable" }
+// { dg-prune-output "k" }
+// { dg-prune-output "\[0-9\]+%" }
+
+template < int> using __conditional_t = int;
+template < typename _Iter >
+concept random_access_iterator = requires { new _Iter; };
+template < typename _Iterator > struct reverse_iterator {
+  using iterator_concept = __conditional_t< random_access_iterator< _Iterator 
>>;
+};
+void RemoveBottom()
+{
+  int iter;
+  for (reverse_iterator< int > iter;;)
+  ;
+}


[gcc r15-1768] c++: Relax too strict assert in stabilize_expr [PR111160]

2024-07-02 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:49058fecbfd09a3354064e7d695b4a1056ce7547

commit r15-1768-g49058fecbfd09a3354064e7d695b4a1056ce7547
Author: Simon Martin 
Date:   Tue Jun 11 11:44:28 2024 +0200

c++: Relax too strict assert in stabilize_expr [PR60]

The case in the ticket is an ICE on invalid due to an assert in 
stabilize_expr,
but the underlying issue can actually trigger on this *valid* code:

=== cut here ===
struct TheClass {
  TheClass() {}
  TheClass(volatile TheClass& t) {}
  TheClass operator=(volatile TheClass& t) volatile { return t; }
};
void the_func() {
  volatile TheClass x, y, z;
  (false ? x : y) = z;
}
=== cut here ===

The problem is that stabilize_expr asserts that it returns an expression
without TREE_SIDE_EFFECTS, which can't be if the involved type is volatile.

This patch relaxes the assert to accept having TREE_THIS_VOLATILE on the
returned expression.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/60

gcc/cp/ChangeLog:

* tree.cc (stabilize_expr): Stabilized expressions can have
TREE_SIDE_EFFECTS if they're volatile.

gcc/testsuite/ChangeLog:

* g++.dg/overload/error8.C: New test.
* g++.dg/overload/volatile2.C: New test.

Diff:
---
 gcc/cp/tree.cc|  2 +-
 gcc/testsuite/g++.dg/overload/error8.C|  9 +
 gcc/testsuite/g++.dg/overload/volatile2.C | 12 
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 28648c14c6d..dfd4a3a948b 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5969,7 +5969,7 @@ stabilize_expr (tree exp, tree* initp)
 }
   *initp = init_expr;
 
-  gcc_assert (!TREE_SIDE_EFFECTS (exp));
+  gcc_assert (!TREE_SIDE_EFFECTS (exp) || TREE_THIS_VOLATILE (exp));
   return exp;
 }
 
diff --git a/gcc/testsuite/g++.dg/overload/error8.C 
b/gcc/testsuite/g++.dg/overload/error8.C
new file mode 100644
index 000..a7e745860e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/error8.C
@@ -0,0 +1,9 @@
+// PR c++/60
+// { dg-do compile { target c++11 } }
+
+class TheClass {}; // { dg-error "discards|bind|discards|bind" }
+void the_func() {
+  TheClass x;
+  volatile TheClass y;
+  (false ? x : x) = y; // { dg-error "ambiguous|ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/overload/volatile2.C 
b/gcc/testsuite/g++.dg/overload/volatile2.C
new file mode 100644
index 000..9f27357aed6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/volatile2.C
@@ -0,0 +1,12 @@
+// PR c++/60
+// { dg-do compile { target c++11 } }
+
+struct TheClass {
+  TheClass() {}
+  TheClass(volatile TheClass& t) {}
+  TheClass operator=(volatile TheClass& t) volatile { return t; }
+};
+void the_func() {
+  volatile TheClass x, y, z;
+  (false ? x : y) = z;
+}


[gcc r15-2792] c++: Fix ICE on valid involving variadic constructor [PR111592]

2024-08-07 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:a1999cbc816ecd382c7af4ca44153379de49dcaf

commit r15-2792-ga1999cbc816ecd382c7af4ca44153379de49dcaf
Author: Simon Martin 
Date:   Wed Aug 7 12:45:12 2024 +0200

c++: Fix ICE on valid involving variadic constructor [PR111592]

We currently ICE upon the following valid code, due to the fix made through
commit 9efe5fbde1e8

=== cut here ===
struct ignore { ignore(...) {} };
template
void InternalCompilerError(Args... args)
{ ignore{ ignore(args) ... }; }
int main() { InternalCompilerError(0, 0); }
=== cut here ===

Change 9efe5fbde1e8 avoids infinite recursion in build_over_call by 
returning
error_mark_node if one invokes ignore::ignore(...) with an argument of type
ignore, because otherwise we end up calling convert_arg_to_ellipsis for that
argument, and recurse into build_over_call with the exact same parameters.

This patch tightens the condition to only return error_mark_node if there's 
one
and only one parameter to the call being processed - otherwise we won't
infinitely recurse.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/111592

gcc/cp/ChangeLog:

* call.cc (build_over_call): Only error out if there's a single
parameter of type A in a call to A::A(...).

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/call.cc   |  1 +
 gcc/testsuite/g++.dg/cpp0x/variadic186.C | 11 +++
 2 files changed, 12 insertions(+)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index a75e2e5e3afd..67d38e2a78a7 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -10365,6 +10365,7 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
  a = decay_conversion (a, complain);
}
   else if (DECL_CONSTRUCTOR_P (fn)
+  && vec_safe_length (args) == 1
   && same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (fn),
 TREE_TYPE (a)))
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic186.C 
b/gcc/testsuite/g++.dg/cpp0x/variadic186.C
new file mode 100644
index ..4a25a1a96bf8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic186.C
@@ -0,0 +1,11 @@
+// PR c++/111592
+// { dg-do compile { target c++11 } }
+
+struct ignore { ignore(...) {} };
+
+template
+void InternalCompilerError(Args... args)
+{ ignore{ ignore(args) ... }; }
+
+int main()
+{ InternalCompilerError(0, 0); }


[gcc r15-2855] c++: Don't accept multiple enum definitions within template class [PR115806]

2024-08-09 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:786ebbd6058540b2110da16a693f0c582c11413c

commit r15-2855-g786ebbd6058540b2110da16a693f0c582c11413c
Author: Simon Martin 
Date:   Thu Aug 8 14:59:49 2024 +0200

c++: Don't accept multiple enum definitions within template class [PR115806]

We have been accepting the following invalid code since revision 557831a91df

=== cut here ===
template  struct S {
  enum E { a };
  enum E { b };
};
S s;
=== cut here ===

The problem is that start_enum will set OPAQUE_ENUM_P to true even if it
retrieves an existing definition for the enum, which causes the redefinition
check in cp_parser_enum_specifier to be bypassed.

This patch only sets OPAQUE_ENUM_P and ENUM_FIXED_UNDERLYING_TYPE_P when
actually pushing a new tag for the enum.

PR c++/115806

gcc/cp/ChangeLog:

* decl.cc (start_enum): Only set OPAQUE_ENUM_P and
ENUM_FIXED_UNDERLYING_TYPE_P when pushing a new tag.

gcc/testsuite/ChangeLog:

* g++.dg/parse/enum15.C: New test.

Diff:
---
 gcc/cp/decl.cc  | 22 --
 gcc/testsuite/g++.dg/parse/enum15.C |  9 +
 2 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a468bfdb7b67..f23b635aec9f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -17059,22 +17059,24 @@ start_enum (tree name, tree enumtype, tree 
underlying_type,
  enumtype = cxx_make_type (ENUMERAL_TYPE);
  enumtype = pushtag (name, enumtype);
 
- /* std::byte aliases anything.  */
- if (enumtype != error_mark_node
- && TYPE_CONTEXT (enumtype) == std_node
- && !strcmp ("byte", TYPE_NAME_STRING (enumtype)))
-   TYPE_ALIAS_SET (enumtype) = 0;
+ if (enumtype != error_mark_node)
+   {
+ /* The enum is considered opaque until the opening '{' of the
+enumerator list.  */
+ SET_OPAQUE_ENUM_P (enumtype, true);
+ ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = !! underlying_type;
+
+ /* std::byte aliases anything.  */
+ if (TYPE_CONTEXT (enumtype) == std_node
+ && !strcmp ("byte", TYPE_NAME_STRING (enumtype)))
+   TYPE_ALIAS_SET (enumtype) = 0;
+   }
}
   else
  enumtype = xref_tag (enum_type, name);
 
   if (enumtype == error_mark_node)
return error_mark_node;
-
-  /* The enum is considered opaque until the opening '{' of the
-enumerator list.  */
-  SET_OPAQUE_ENUM_P (enumtype, true);
-  ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = !! underlying_type;
 }
 
   SET_SCOPED_ENUM_P (enumtype, scoped_enum_p);
diff --git a/gcc/testsuite/g++.dg/parse/enum15.C 
b/gcc/testsuite/g++.dg/parse/enum15.C
new file mode 100644
index ..d19262156b91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/enum15.C
@@ -0,0 +1,9 @@
+// PR c++/115806
+// { dg-do compile }
+
+template 
+struct S {
+  enum E { a }; // { dg-note "previous definition" }
+  enum E { b }; // { dg-error "multiple definition" }
+};
+S s;


[gcc r15-847] Add testcase for PR c++/105229: ICE in lookup_template_class_1

2024-05-27 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:88c9b96b2800ddb7a499bd10abaa9441a471d5fe

commit r15-847-g88c9b96b2800ddb7a499bd10abaa9441a471d5fe
Author: Simon Martin 
Date:   Fri May 24 10:56:36 2024 +0200

Add testcase for PR c++/105229: ICE in lookup_template_class_1

The test case in PR c++/105229 has been fixed since 11.4 (via
PR c++/106024) - the attached patch simply adds the case to
the test suite.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/105229

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash72.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/parse/crash72.C | 12 
 1 file changed, 12 insertions(+)

diff --git a/gcc/testsuite/g++.dg/parse/crash72.C 
b/gcc/testsuite/g++.dg/parse/crash72.C
new file mode 100644
index 000..df469e20f28
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash72.C
@@ -0,0 +1,12 @@
+// PR c++/105229
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-Wno-missing-template-keyword" }
+
+template  void bar ()
+{
+  []  {}.operator () <> (); // { dg-error "expected primary-expression" }
+}
+void foo ()
+{
+  bar ();
+}


[gcc r15-972] Fix PR c++/109958: ICE taking the address of bound static member function brought into derived class

2024-06-02 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:47827293551a3ec339617678c8e938c8ca3790f1

commit r15-972-g47827293551a3ec339617678c8e938c8ca3790f1
Author: Simon Martin 
Date:   Sun Jun 2 17:45:04 2024 +0200

Fix PR c++/109958: ICE taking the address of bound static member function 
brought into derived class by using-declaration

We currently ICE upon the following because we don't properly handle the
overload created for B::f through the using statement.

=== cut here ===
struct B { static int f(); };
struct D : B { using B::f; };
void f(D d) { &d.f; }
=== cut here ===

This patch makes build_class_member_access_expr and cp_build_addr_expr_1 
handle
such overloads, and fixes the PR.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/109958

gcc/cp/ChangeLog:

* typeck.cc (build_class_member_access_expr): Handle single 
OVERLOADs.
(cp_build_addr_expr_1): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/overload/using6.C: New test.

Diff:
---
 gcc/cp/typeck.cc   | 5 +
 gcc/testsuite/g++.dg/overload/using6.C | 5 +
 2 files changed, 10 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 1b7a31d32f3..5970ac3d398 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3025,6 +3025,8 @@ build_class_member_access_expr (cp_expr object, tree 
member,
 know the type of the expression.  Otherwise, we must wait
 until overload resolution has been performed.  */
   functions = BASELINK_FUNCTIONS (member);
+  if (TREE_CODE (functions) == OVERLOAD && OVL_SINGLE_P (functions))
+   functions = OVL_FIRST (functions);
   if (TREE_CODE (functions) == FUNCTION_DECL
  && DECL_STATIC_FUNCTION_P (functions))
type = TREE_TYPE (functions);
@@ -7333,6 +7335,9 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, 
tsubst_flags_t complain)
 {
   tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
 
+  if (TREE_CODE (fn) == OVERLOAD && OVL_SINGLE_P (fn))
+   fn = OVL_FIRST (fn);
+
   /* We can only get here with a single static member
 function.  */
   gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
diff --git a/gcc/testsuite/g++.dg/overload/using6.C 
b/gcc/testsuite/g++.dg/overload/using6.C
new file mode 100644
index 000..4f89f68a30f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/using6.C
@@ -0,0 +1,5 @@
+// PR c++/109958
+
+struct B { static int f(); };
+struct D : B { using B::f; };
+void f(D d) { &d.f; }


[gcc r15-1016] Fix PR c++/111106: missing ; causes internal compiler error

2024-06-04 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:cfbd8735359d84a2d716549415eac70e885167bf

commit r15-1016-gcfbd8735359d84a2d716549415eac70e885167bf
Author: Simon Martin 
Date:   Fri May 24 17:00:17 2024 +0200

Fix PR c++/06: missing ; causes internal compiler error

We currently fail upon the following because an assert in dependent_type_p
fails for f's parameter

=== cut here ===
consteval int id (int i) { return i; }
constexpr int
f (auto i) requires requires { id (i) } { return i; }
void g () { f (42); }
=== cut here ===

This patch fixes this by relaxing the assert to pass during error recovery.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/06

gcc/cp/ChangeLog:

* pt.cc (dependent_type_p): Don't fail assert during error recovery.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/consteval37.C: New test.

Diff:
---
 gcc/cp/pt.cc |  3 ++-
 gcc/testsuite/g++.dg/cpp2a/consteval37.C | 16 
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dfce1b3c359..edb94a000ea 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -28019,7 +28019,8 @@ dependent_type_p (tree type)
   /* If we are not processing a template, then nobody should be
 providing us with a dependent type.  */
   gcc_assert (type);
-  gcc_assert (TREE_CODE (type) != TEMPLATE_TYPE_PARM || is_auto (type));
+  gcc_assert (TREE_CODE (type) != TEMPLATE_TYPE_PARM || is_auto (type)
+ || seen_error());
   return false;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval37.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval37.C
new file mode 100644
index 000..519d83d9bf8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval37.C
@@ -0,0 +1,16 @@
+// PR c++/06
+// { dg-do compile { target c++20 } }
+
+consteval int id (int i) { return i; }
+
+constexpr int f (auto i)
+  requires requires { id (i) } // { dg-error "expected" }
+{
+  return i;
+}
+
+void g () {
+  f (42);
+}
+
+// { dg-excess-errors "" }


[gcc r15-1017] Add missing space after seen_error in gcc/cp/pt.cc

2024-06-04 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:54e5cbcd82e36f5aa8205b56880821eea25701ae

commit r15-1017-g54e5cbcd82e36f5aa8205b56880821eea25701ae
Author: Simon Martin 
Date:   Tue Jun 4 17:27:25 2024 +0200

Add missing space after seen_error in gcc/cp/pt.cc

I realized that I committed a change with a missing space after seen_error.
This fixes it, as well as another occurrence in the same file.

Apologies for the mistake - I'll commit this as obvious.

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr): Add missing space after seen_error.
(dependent_type_p): Likewise.

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

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index edb94a000ea..8cbcf7cdf7a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20918,7 +20918,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
   be using lambdas anyway, so it's ok to be
   stricter.  Be strict with C++20 template-id ADL too.
   And be strict if we're already failing anyway.  */
-   bool strict = in_lambda || template_id_p || seen_error();
+   bool strict = in_lambda || template_id_p || seen_error ();
bool diag = true;
if (strict)
  error_at (cp_expr_loc_or_input_loc (t),
@@ -28020,7 +28020,7 @@ dependent_type_p (tree type)
 providing us with a dependent type.  */
   gcc_assert (type);
   gcc_assert (TREE_CODE (type) != TEMPLATE_TYPE_PARM || is_auto (type)
- || seen_error());
+ || seen_error ());
   return false;
 }


[gcc r15-1019] c++: Add testcase for PR103338

2024-06-04 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:126ccf8ffc46865accec22a2789f09abd98c1d85

commit r15-1019-g126ccf8ffc46865accec22a2789f09abd98c1d85
Author: Simon Martin 
Date:   Tue Jun 4 11:59:31 2024 +0200

c++: Add testcase for PR103338

The case in that PR used to ICE until commit f04dc89. This patch simply adds
the case to the testsuite.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/103388

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash73.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/parse/crash73.C | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/gcc/testsuite/g++.dg/parse/crash73.C 
b/gcc/testsuite/g++.dg/parse/crash73.C
new file mode 100644
index 000..97b8b5e8325
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash73.C
@@ -0,0 +1,19 @@
+// PR c++/103338
+// { dg-do compile { target c++11 } }
+
+template
+struct zip_view {
+  struct Iterator;
+};
+
+template
+struct zip_transform_view;
+
+template
+struct zip_view::Iterator { // { dg-error "no class template" }
+  template
+  template
+  friend class zip_transform_view::Iterator;
+};
+
+zip_view<>::Iterator iter;


[gcc r15-1102] lto: Fix build on MacOS

2024-06-07 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:a3d68b5155018817dd7eef5abbaeadf3959b8e5e

commit r15-1102-ga3d68b5155018817dd7eef5abbaeadf3959b8e5e
Author: Simon Martin 
Date:   Fri Jun 7 16:14:58 2024 +0200

lto: Fix build on MacOS

The build fails on x86_64-apple-darwin19.6.0 starting with 5b6d5a886ee 
because
vector is included after system.h and runs into poisoned identifiers.

This patch fixes this by defining INCLUDE_VECTOR before including system.h.

Validated by doing a full build on x86_64-apple-darwin19.6.0.

gcc/lto/ChangeLog:

* lto-partition.cc: Define INCLUDE_VECTOR to avoid running into
poisoned identifiers.

Diff:
---
 gcc/lto/lto-partition.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/lto/lto-partition.cc b/gcc/lto/lto-partition.cc
index 44b457d0b2a..2238650fa0e 100644
--- a/gcc/lto/lto-partition.cc
+++ b/gcc/lto/lto-partition.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3.  If not see
 .  */
 
 #include "config.h"
+#define INCLUDE_VECTOR
 #include "system.h"
 #include "coretypes.h"
 #include "target.h"
@@ -38,7 +39,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-partition.h"
 
 #include 
-#include 
 
 vec ltrans_partitions;


[gcc r15-1105] c++: Handle erroneous DECL_LOCAL_DECL_ALIAS in duplicate_decls [PR107575]

2024-06-07 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:0ce138694a6b40708a80691fa4003f6af1defa49

commit r15-1105-g0ce138694a6b40708a80691fa4003f6af1defa49
Author: Simon Martin 
Date:   Tue Jun 4 21:20:23 2024 +0200

c++: Handle erroneous DECL_LOCAL_DECL_ALIAS in duplicate_decls [PR107575]

We currently ICE upon the following because we don't properly handle local
functions with an error_mark_node as DECL_LOCAL_DECL_ALIAS in 
duplicate_decls.

=== cut here ===
void f (void) {
  virtual int f (void) const;
  virtual int f (void);
}
=== cut here ===

This patch fixes this by checking for error_mark_node.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/107575

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): Check for error_mark_node
DECL_LOCAL_DECL_ALIAS.

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash74.C: New test.

Diff:
---
 gcc/cp/decl.cc   | 11 +++
 gcc/testsuite/g++.dg/parse/crash74.C | 11 +++
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d481e1ec074..03deb1493a4 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2792,10 +2792,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
  retrofit_lang_decl (newdecl);
  tree alias = DECL_LOCAL_DECL_ALIAS (newdecl)
= DECL_LOCAL_DECL_ALIAS (olddecl);
- DECL_ATTRIBUTES (alias)
-   = (*targetm.merge_decl_attributes) (alias, newdecl);
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
-   merge_attribute_bits (newdecl, alias);
+ if (alias != error_mark_node)
+   {
+ DECL_ATTRIBUTES (alias)
+   = (*targetm.merge_decl_attributes) (alias, newdecl);
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+   merge_attribute_bits (newdecl, alias);
+   }
}
 }
 
diff --git a/gcc/testsuite/g++.dg/parse/crash74.C 
b/gcc/testsuite/g++.dg/parse/crash74.C
new file mode 100644
index 000..a7ba5094be6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash74.C
@@ -0,0 +1,11 @@
+// PR c++/107575
+
+void f (void) {
+  virtual int f (void) const; // { dg-line line_4 }
+  virtual int f (void); // { dg-line line_5 }
+}
+
+// { dg-error "outside class declaration" {} { target *-*-* } line_4 }
+// { dg-error "cannot have cv-qualifier" {} { target *-*-* } line_4 }
+// { dg-error "ambiguating new declaration of" {} { target *-*-* } line_4 }
+// { dg-error "outside class declaration" {} { target *-*-* } line_5 }


[gcc r15-1114] c++: Make *_cast<*> parsing more robust to errors [PR108438]

2024-06-08 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:2c9643c27ecddb7f597d34009d89e932b4aca58e

commit r15-1114-g2c9643c27ecddb7f597d34009d89e932b4aca58e
Author: Simon Martin 
Date:   Fri Jun 7 11:21:07 2024 +0200

c++: Make *_cast<*> parsing more robust to errors [PR108438]

We ICE upon the following when trying to emit a -Wlogical-not-parentheses
warning:

=== cut here ===
template  T foo (T arg, T& ref, T* ptr) {
  int a = 1;
  return static_cast(a);
}
=== cut here ===

This patch makes *_cast<*> parsing more robust by skipping to the closing 
'>'
upon error in the target type.

Successfully tested on x86_64-pc-linux-gnu.

PR c++/108438

gcc/cp/ChangeLog:

* parser.cc (cp_parser_postfix_expression): Use
cp_parser_require_end_of_template_parameter_list to skip to the 
closing
'>' upon error parsing the target type of *_cast<*> expressions.

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash75.C: New test.

Diff:
---
 gcc/cp/parser.cc | 2 +-
 gcc/testsuite/g++.dg/parse/crash75.C | 9 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index bc4a2359153..9f43a776889 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -7569,7 +7569,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool 
address_p, bool cast_p,
  NULL);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
/* Look for the closing `>'.  */
-   cp_parser_require (parser, CPP_GREATER, RT_GREATER);
+   cp_parser_require_end_of_template_parameter_list (parser);
/* Restore the old message.  */
parser->type_definition_forbidden_message = saved_message;
 
diff --git a/gcc/testsuite/g++.dg/parse/crash75.C 
b/gcc/testsuite/g++.dg/parse/crash75.C
new file mode 100644
index 000..81a16e35b14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash75.C
@@ -0,0 +1,9 @@
+// PR c++/108438
+// { dg-options "-Wlogical-not-parentheses" }
+
+template 
+T foo (T arg, T& ref, T* ptr)
+{
+  int a = 1;
+  return static_cast(a); // { dg-error "expected" }
+}


[gcc r15-4301] Revert "c++: Fix overeager Woverloaded-virtual with conversion operators [PR109918]"

2024-10-13 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:a4eec6c712ec16a77eb28ae0a7366d957a2c0080

commit r15-4301-ga4eec6c712ec16a77eb28ae0a7366d957a2c0080
Author: Simon Martin 
Date:   Sun Oct 13 17:58:14 2024 +0200

Revert "c++: Fix overeager Woverloaded-virtual with conversion operators 
[PR109918]"

This reverts commit 60163c85730e6b7c566e219222403ac87ddbbddd.

Diff:
---
 gcc/cp/class.cc   | 85 ++-
 gcc/cp/error.cc   |  3 +-
 gcc/testsuite/g++.dg/warn/Woverloaded-virt1.C |  2 -
 gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C | 12 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt6.C | 12 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt7.C | 25 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt8.C | 15 -
 gcc/testsuite/g++.dg/warn/Woverloaded-virt9.C | 14 -
 8 files changed, 33 insertions(+), 135 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index f754886a60ab..646072d4f202 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -3243,15 +3243,10 @@ warn_hidden (tree t)
  continue;
 
tree name = OVL_NAME (fns);
-   size_t num_fns = 0; /* The number of fndecls in fns.  */
auto_vec base_fndecls;
tree base_binfo;
tree binfo;
unsigned j;
-   hash_set overriden_base_fndecls;
-   /* base_fndecls that are hidden but not overriden. The "value"
-  contains the fndecl that hides the "key".  */
-   hash_map hidden_base_fndecls;
 
if (IDENTIFIER_CDTOR_P (name))
  continue;
@@ -3269,63 +3264,47 @@ warn_hidden (tree t)
if (base_fndecls.is_empty ())
  continue;
 
-   /* Find all the base_fndecls that are overridden, as well as those
-  that are hidden, in T.  */
+   /* Remove any overridden functions.  */
+   bool seen_non_override = false;
for (tree fndecl : ovl_range (fns))
  {
-   fndecl = STRIP_TEMPLATE (fndecl);
+   bool any_override = false;
if (TREE_CODE (fndecl) == FUNCTION_DECL
-   && fndecl != conv_op_marker)
+   && DECL_VINDEX (fndecl))
  {
-   num_fns++;
-   tree fndecl_vindex = DECL_VINDEX (fndecl);
-   /* If the method from the base class has the same DECL_VINDEX
-  as the method from the derived, it has been overridden.
-  Note that we can't move on after finding one match: fndecl
-  might override multiple base fns.  */
+   /* If the method from the base class has the same
+  signature as the method from the derived class, it
+  has been overridden.  Note that we can't move on
+  after finding one match: fndecl might override
+  multiple base fns.  */
for (size_t k = 0; k < base_fndecls.length (); k++)
- {
-   if (!base_fndecls[k] || !DECL_VINDEX (base_fndecls[k]))
- continue;
-   tree base_fndecl_vindex = DECL_VINDEX (base_fndecls[k]);
-   if (fndecl_vindex
-   && !tree_int_cst_compare (fndecl_vindex,
- base_fndecl_vindex))
- overriden_base_fndecls.add (base_fndecls[k]);
-   else if (IDENTIFIER_CONV_OP_P (name)
-&& (DECL_NAME (fndecl)
-!= DECL_NAME (base_fndecls[k])))
- /* If base_fndecl[k] and fndecl are conversion operators
-to different types, they're unrelated.  */
- ;
-   else
- hidden_base_fndecls.put (base_fndecls[k], fndecl);
- }
+ if (base_fndecls[k]
+ && same_signature_p (fndecl, base_fndecls[k]))
+   {
+ base_fndecls[k] = NULL_TREE;
+ any_override = true;
+   }
  }
+   if (!any_override)
+ seen_non_override = true;
  }
 
-   if (warn_overloaded_virtual == 1
-   && overriden_base_fndecls.elements () == num_fns)
- /* All the fns override a base virtual.  */
- continue;
+   if (!seen_non_override && warn_overloaded_virtual == 1)
+ /* All the derived fns override base virtuals.  */
+ return;
 
-   /* Now give a warning for all hidden methods. Note that a method that
-  is both in hidden_base_fndecls and overriden_base_fndecls is not
-  hidden.  */
-   for (auto hidden_base_fndecl : hidden_base_fndecls)
- {
-   tree hidden_fndecl = hidden_base_fndecl.first;
-   tree hider = hidden_base_fndecl.second;
-   if (!hidden_fndecl
-   || overriden_base_fndecls.contains (hidden_fndecl))
- continue;
-   gcc_assert (hider

[gcc r15-4238] libiberty: Restore build with CP_DEMANGLE_DEBUG defined

2024-10-10 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:c1b2100e736c8ad80479fa6417db760695a00256

commit r15-4238-gc1b2100e736c8ad80479fa6417db760695a00256
Author: Simon Martin 
Date:   Thu Oct 10 15:29:32 2024 +0200

libiberty: Restore build with CP_DEMANGLE_DEBUG defined

cp-demangle.c does not build when CP_DEMANGLE_DEBUG is defined since
r13-2887-gb04208895fed34. This trivial patch fixes the issue.

libiberty/ChangeLog:

* cp-demangle.c (d_dump): Fix compilation when CP_DEMANGLE_DEBUG
is defined.

Diff:
---
 libiberty/cp-demangle.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index fc2cf64e6e01..5b1bd5dff227 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -655,9 +655,9 @@ d_dump (struct demangle_component *dc, int indent)
   return;
 case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
   {
-   char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 };
+   char suffix[2] = { dc->u.s_extended_builtin.suffix, 0 };
printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name,
-   dc->u.s_extended_builtin.type->arg, suffix);
+   dc->u.s_extended_builtin.arg, suffix);
   }
   return;
 case DEMANGLE_COMPONENT_OPERATOR:


[gcc r15-4282] c++: Fix overeager Woverloaded-virtual with conversion operators [PR109918]

2024-10-12 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:60163c85730e6b7c566e219222403ac87ddbbddd

commit r15-4282-g60163c85730e6b7c566e219222403ac87ddbbddd
Author: Simon Martin 
Date:   Fri Oct 11 10:16:26 2024 +0200

c++: Fix overeager Woverloaded-virtual with conversion operators [PR109918]

We currently emit an incorrect -Woverloaded-virtual warning upon the
following test case

=== cut here ===
struct A {
  virtual operator int() { return 42; }
  virtual operator char() = 0;
};
struct B : public A {
  operator char() { return 'A'; }
};
=== cut here ===

The problem is that when iterating over ovl_range (fns), warn_hidden
gets confused by the conversion operator marker, concludes that
seen_non_override is true and therefore emits a warning for all
conversion operators in A that do not convert to char, even if
-Woverloaded-virtual is 1 (e.g. with -Wall, the case reported).

A second set of problems is highlighted when -Woverloaded-virtual is 2.

First, with the same test case, since base_fndecls contains all
conversion operators in A (except the one to char, that's been removed
when iterating over ovl_range (fns)), we emit a spurious warning for
the conversion operator to int, even though it's unrelated.

Second, in case there are several conversion operators with different
cv-qualifiers to the same type in A, we rightfully emit a warning,
however the note uses the location of the conversion operator marker
instead of the right one; location_of should go over conv_op_marker.

This patch fixes all these by explicitly keeping track of (1) base
methods that are overriden, as well as (2) base methods that are hidden
but not overriden (and by what), and warning about methods that are in
(2) but not (1). It also ignores non virtual base methods, per
"definition" of -Woverloaded-virtual.

PR c++/109918

gcc/cp/ChangeLog:

* class.cc (warn_hidden): Keep track of overloaded and of hidden
base methods. Mention the actual hiding function in the warning,
not the first overload.
* error.cc (location_of): Skip over conv_op_marker.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Woverloaded-virt1.C: Check that no warning is
emitted for non virtual base methods.
* g++.dg/warn/Woverloaded-virt5.C: New test.
* g++.dg/warn/Woverloaded-virt6.C: New test.
* g++.dg/warn/Woverloaded-virt7.C: New test.
* g++.dg/warn/Woverloaded-virt8.C: New test.
* g++.dg/warn/Woverloaded-virt9.C: New test.

Diff:
---
 gcc/cp/class.cc   | 85 +--
 gcc/cp/error.cc   |  3 +-
 gcc/testsuite/g++.dg/warn/Woverloaded-virt1.C |  2 +
 gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C | 12 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt6.C | 12 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt7.C | 25 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt8.C | 15 +
 gcc/testsuite/g++.dg/warn/Woverloaded-virt9.C | 14 +
 8 files changed, 135 insertions(+), 33 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 646072d4f202..f754886a60ab 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -3243,10 +3243,15 @@ warn_hidden (tree t)
  continue;
 
tree name = OVL_NAME (fns);
+   size_t num_fns = 0; /* The number of fndecls in fns.  */
auto_vec base_fndecls;
tree base_binfo;
tree binfo;
unsigned j;
+   hash_set overriden_base_fndecls;
+   /* base_fndecls that are hidden but not overriden. The "value"
+  contains the fndecl that hides the "key".  */
+   hash_map hidden_base_fndecls;
 
if (IDENTIFIER_CDTOR_P (name))
  continue;
@@ -3264,47 +3269,63 @@ warn_hidden (tree t)
if (base_fndecls.is_empty ())
  continue;
 
-   /* Remove any overridden functions.  */
-   bool seen_non_override = false;
+   /* Find all the base_fndecls that are overridden, as well as those
+  that are hidden, in T.  */
for (tree fndecl : ovl_range (fns))
  {
-   bool any_override = false;
+   fndecl = STRIP_TEMPLATE (fndecl);
if (TREE_CODE (fndecl) == FUNCTION_DECL
-   && DECL_VINDEX (fndecl))
+   && fndecl != conv_op_marker)
  {
-   /* If the method from the base class has the same
-  signature as the method from the derived class, it
-  has been overridden.  Note that we can't move on
-  after finding one match: fndecl might override
-  multiple base fns.  */
+   num_fns++;
+   tree fndecl_vindex = DECL_VINDEX (fndecl);
+   /* If the method from the base class has the same DECL_VINDEX
+  

[gcc r15-4957] c++: Defer -fstrong-eval-order processing to template instantiation time [PR117158]

2024-11-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:b1d92aeb8583c8d1491c97703680c5fb88ed1fe4

commit r15-4957-gb1d92aeb8583c8d1491c97703680c5fb88ed1fe4
Author: Simon Martin 
Date:   Tue Nov 5 10:07:42 2024 +0100

c++: Defer -fstrong-eval-order processing to template instantiation time 
[PR117158]

Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template  struct Sub : public Base {
  bool Get(int i) {
return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR. We do so at
template declaration time, and end up calling contains_placeholder_p
with a SCOPE_REF, that it does not handle well.

This patch fixes this by deferring the wrapping into SAVE_EXPR to
instantiation time for templates, when the SCOPE_REF will have been
turned into a COMPONENT_REF.

PR c++/117158

gcc/cp/ChangeLog:

* typeck.cc (cp_build_array_ref): Only wrap array expression
into a SAVE_EXPR at template instantiation time.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/eval-order13.C: New test.
* g++.dg/parse/crash77.C: New test.

Diff:
---
 gcc/cp/typeck.cc  |  3 ++-
 gcc/testsuite/g++.dg/cpp1z/eval-order13.C | 29 +
 gcc/testsuite/g++.dg/parse/crash77.C  | 13 +
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 6ce1bb61fe7b..439681216bed 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4092,7 +4092,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 tree ar = cp_default_conversion (array, complain);
 tree ind = cp_default_conversion (idx, complain);
 
-if (!first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+if (!processing_template_decl
+   && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
   ar = first = save_expr (ar);
 
 /* Put the integer in IND to simplify error checking.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order13.C 
b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
new file mode 100644
index ..6e8ebeb30967
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
@@ -0,0 +1,29 @@
+// PR c++/117158 - Similar to eval-order7.C, only with templates.
+// { dg-do run { target c++11 } }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b[4] = { 5, 6, 7, 8 };
+
+struct Base {
+  int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  int Get(int i) {
+Base::intarray = a;
+int r = Base::intarray[(Base::intarray = b, i)];
+if (Base::intarray != b)
+  __builtin_abort ();
+return r;
+  }
+};
+
+int
+main ()
+{
+  Sub s;
+  if (s.Get (3) != 4)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash77.C 
b/gcc/testsuite/g++.dg/parse/crash77.C
new file mode 100644
index ..729362eb5991
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash77.C
@@ -0,0 +1,13 @@
+// PR c++/117158
+// { dg-do "compile" }
+
+struct Base {
+  unsigned int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  bool Get(int i) {
+return (Base::intarray[++i] == 0);
+  }
+};


[gcc r15-4958] c++: Don't crash upon invalid placement new operator [PR117101]

2024-11-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:5821f5c8c89a054e34cea00e042996dfdcd7e102

commit r15-4958-g5821f5c8c89a054e34cea00e042996dfdcd7e102
Author: Simon Martin 
Date:   Tue Nov 5 10:16:39 2024 +0100

c++: Don't crash upon invalid placement new operator [PR117101]

We currently crash upon the following invalid code (notice the "void
void**" parameter)

=== cut here ===
using size_t = decltype(sizeof(int));
void *operator new(size_t, void void **p) noexcept { return p; }
int x;
void f() {
int y;
new (&y) int(x);
}
=== cut here ===

The problem is that in this case, we end up with a NULL_TREE parameter
list for the new operator because of the error, and (1) coerce_new_type
wrongly complains about the first parameter type not being size_t,
(2) std_placement_new_fn_p blindly accesses the parameter list, hence a
crash.

This patch does NOT address #1 since we can't easily distinguish between
a new operator declaration without parameters from one with erroneous
parameters (and it's not worth the risk to refactor and break things for
an error recovery issue) hence a dg-bogus in new52.C, but it does
address #2 and the ICE by simply checking the first parameter against
NULL_TREE.

It also adds a new testcase checking that we complain about new
operators with no or invalid first parameters, since we did not have
any.

PR c++/117101

gcc/cp/ChangeLog:

* init.cc (std_placement_new_fn_p): Check first_arg against
NULL_TREE.

gcc/testsuite/ChangeLog:

* g++.dg/init/new52.C: New test.
* g++.dg/init/new53.C: New test.

Diff:
---
 gcc/cp/init.cc|  5 +++--
 gcc/testsuite/g++.dg/init/new52.C | 14 ++
 gcc/testsuite/g++.dg/init/new53.C |  8 
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 0527f53550db..12c673efb2ac 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -2980,8 +2980,9 @@ std_placement_new_fn_p (tree alloc_fn)
   if (DECL_NAMESPACE_SCOPE_P (alloc_fn))
 {
   tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
-  if ((TREE_VALUE (first_arg) == ptr_type_node)
- && TREE_CHAIN (first_arg) == void_list_node)
+  if (first_arg
+ && (TREE_VALUE (first_arg) == ptr_type_node)
+ && (TREE_CHAIN (first_arg) == void_list_node))
return true;
 }
   return false;
diff --git a/gcc/testsuite/g++.dg/init/new52.C 
b/gcc/testsuite/g++.dg/init/new52.C
new file mode 100644
index ..5eee2135724d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new52.C
@@ -0,0 +1,14 @@
+// PR c++/117101
+// { dg-do "compile" { target c++11 } }
+
+using size_t = decltype(sizeof(int));
+void* operator new(size_t, // { dg-bogus "first parameter" "" { xfail *-*-* } }
+  void void **p) noexcept // { dg-error "two or more" }
+{
+  return p; // { dg-error "not declared" }
+}
+int x;
+void f() {
+int y;
+new (&y) int(x);
+}
diff --git a/gcc/testsuite/g++.dg/init/new53.C 
b/gcc/testsuite/g++.dg/init/new53.C
new file mode 100644
index ..93d49dbd6c1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new53.C
@@ -0,0 +1,8 @@
+// Check that we reject operator new with no argument or non-size_t first
+// argument.
+// { dg-do "compile" }
+
+void* operator new(); // { dg-error "takes type .size_t." }
+void* operator new(char); // { dg-error "takes type .size_t." }
+void* operator new(char*); // { dg-error "takes type .size_t." }
+void* operator new(char&); // { dg-error "takes type .size_t." }


[gcc r15-4959] c++: Fix crash during NRV optimization with invalid input [PR117099, PR117129]

2024-11-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:f31b72b75ef7cde61469c774162db7b1cc4c3d03

commit r15-4959-gf31b72b75ef7cde61469c774162db7b1cc4c3d03
Author: Simon Martin 
Date:   Tue Nov 5 10:44:34 2024 +0100

c++: Fix crash during NRV optimization with invalid input [PR117099, 
PR117129]

PR117099 and PR117129 are ICEs upon invalid code that happen when NRVO
is activated, and both due to the fact that we don't consistently set
current_function_return_value to error_mark_node upon error in
finish_return_expr.

This patch fixes this inconsistency which fixes both cases since we skip
calling finalize_nrv when current_function_return_value is
error_mark_node.

PR c++/117099
PR c++/117129

gcc/cp/ChangeLog:

* typeck.cc (check_return_expr): Upon error, set
current_function_return_value to error_mark_node.

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash78.C: New test.
* g++.dg/parse/crash78a.C: New test.
* g++.dg/parse/crash79.C: New test.

Diff:
---
 gcc/cp/typeck.cc  |  8 +++-
 gcc/testsuite/g++.dg/parse/crash78.C  | 15 +++
 gcc/testsuite/g++.dg/parse/crash78a.C | 22 ++
 gcc/testsuite/g++.dg/parse/crash79.C  | 15 +++
 4 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 439681216bed..4c15e26f692a 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -11239,6 +11239,8 @@ check_return_expr (tree retval, bool *no_warning, bool 
*dangling)
   "function returning %qT", valtype);
   /* Remember that this function did return.  */
   current_function_returns_value = 1;
+  /* But suppress NRV  .*/
+  current_function_return_value = error_mark_node;
   /* And signal caller that TREE_NO_WARNING should be set on the
 RETURN_EXPR to avoid control reaches end of non-void function
 warnings in tree-cfg.cc.  */
@@ -11449,7 +11451,11 @@ check_return_expr (tree retval, bool *no_warning, bool 
*dangling)
 
   /* If the conversion failed, treat this just like `return;'.  */
   if (retval == error_mark_node)
-   return retval;
+   {
+ /* And suppress NRV.  */
+ current_function_return_value = error_mark_node;
+ return retval;
+   }
   /* We can't initialize a register from a AGGR_INIT_EXPR.  */
   else if (! cfun->returns_struct
   && TREE_CODE (retval) == TARGET_EXPR
diff --git a/gcc/testsuite/g++.dg/parse/crash78.C 
b/gcc/testsuite/g++.dg/parse/crash78.C
new file mode 100644
index ..f30fe08df54b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash78.C
@@ -0,0 +1,15 @@
+// PR c++/117099
+// { dg-do "compile" }
+
+struct X {
+  ~X();
+};
+
+X test(bool b) {
+  {
+X x;
+return x;
+  }
+  return X();
+  if (!(b)) return; // { dg-error "return-statement with no value" }
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash78a.C 
b/gcc/testsuite/g++.dg/parse/crash78a.C
new file mode 100644
index ..241a5e390dee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash78a.C
@@ -0,0 +1,22 @@
+// PR c++/117099
+// With -fpermissive, make sure we don't do NRV in this case, but keep
+// executing fine. Note that the return at line 16 is undefined behaviour.
+// { dg-do "run" }
+// { dg-options "-fpermissive" }
+
+struct X {
+  ~X() {}
+};
+
+X test(bool b) {
+  X x;
+  if (b)
+return x;
+  else
+return; // { dg-warning "return-statement with no value" }
+}
+
+int main(int, char*[]) {
+  (void) test (false);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash79.C 
b/gcc/testsuite/g++.dg/parse/crash79.C
new file mode 100644
index ..08d62af39c62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash79.C
@@ -0,0 +1,15 @@
+// PR c++/117129
+// { dg-do "compile" { target c++11 } }
+
+struct Noncopyable {
+  Noncopyable();
+  Noncopyable(const Noncopyable &) = delete; // { dg-note "declared here" }
+  virtual ~Noncopyable();
+};
+Noncopyable nrvo() { 
+  {
+Noncopyable A;
+return A; // { dg-error "use of deleted function" }
+ // { dg-note "display considered" "" { target *-*-* } .-1 }
+  }
+}


[gcc r12-10804] c++: Defer -fstrong-eval-order processing to template instantiation time [PR117158]

2024-11-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:5fdd38d576c20d5a337b5c7d14108981d0751434

commit r12-10804-g5fdd38d576c20d5a337b5c7d14108981d0751434
Author: Simon Martin 
Date:   Tue Nov 5 10:07:42 2024 +0100

c++: Defer -fstrong-eval-order processing to template instantiation time 
[PR117158]

Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template  struct Sub : public Base {
  bool Get(int i) {
return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR. We do so at
template declaration time, and end up calling contains_placeholder_p
with a SCOPE_REF, that it does not handle well.

This patch fixes this by deferring the wrapping into SAVE_EXPR to
instantiation time for templates, when the SCOPE_REF will have been
turned into a COMPONENT_REF.

PR c++/117158

gcc/cp/ChangeLog:

* typeck.cc (cp_build_array_ref): Only wrap array expression
into a SAVE_EXPR at template instantiation time.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/eval-order13.C: New test.
* g++.dg/parse/crash77.C: New test.

(cherry picked from commit b1d92aeb8583c8d1491c97703680c5fb88ed1fe4)

Diff:
---
 gcc/cp/typeck.cc  |  3 ++-
 gcc/testsuite/g++.dg/cpp1z/eval-order13.C | 29 +
 gcc/testsuite/g++.dg/parse/crash77.C  | 13 +
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index ff8f0ef00838..df819701d4a6 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3919,7 +3919,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 tree ar = cp_default_conversion (array, complain);
 tree ind = cp_default_conversion (idx, complain);
 
-if (!first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+if (!processing_template_decl
+   && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
   ar = first = save_expr (ar);
 
 /* Put the integer in IND to simplify error checking.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order13.C 
b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
new file mode 100644
index ..6e8ebeb30967
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
@@ -0,0 +1,29 @@
+// PR c++/117158 - Similar to eval-order7.C, only with templates.
+// { dg-do run { target c++11 } }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b[4] = { 5, 6, 7, 8 };
+
+struct Base {
+  int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  int Get(int i) {
+Base::intarray = a;
+int r = Base::intarray[(Base::intarray = b, i)];
+if (Base::intarray != b)
+  __builtin_abort ();
+return r;
+  }
+};
+
+int
+main ()
+{
+  Sub s;
+  if (s.Get (3) != 4)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash77.C 
b/gcc/testsuite/g++.dg/parse/crash77.C
new file mode 100644
index ..729362eb5991
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash77.C
@@ -0,0 +1,13 @@
+// PR c++/117158
+// { dg-do "compile" }
+
+struct Base {
+  unsigned int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  bool Get(int i) {
+return (Base::intarray[++i] == 0);
+  }
+};


[gcc r15-4843] c++: Add testcase for now fixed issue [PR101887]

2024-11-01 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:fe919da3c395d2214ffc81ad4f51f8344ad5a5c1

commit r15-4843-gfe919da3c395d2214ffc81ad4f51f8344ad5a5c1
Author: Simon Martin 
Date:   Thu Oct 31 15:41:11 2024 +0100

c++: Add testcase for now fixed issue [PR101887]

The testcase in PR101887 has been working since the fix for PR104846,
via r12-7599-gac8310dd122172.

This patch simply adds the case to the testsuite.

PR c++/101887

gcc/testsuite/ChangeLog:

* g++.dg/init/delete5.C: Add testcase from PR c++/101887.

Diff:
---
 gcc/testsuite/g++.dg/init/delete5.C | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/init/delete5.C 
b/gcc/testsuite/g++.dg/init/delete5.C
index 3555f43bbb09..3fff93d846ec 100644
--- a/gcc/testsuite/g++.dg/init/delete5.C
+++ b/gcc/testsuite/g++.dg/init/delete5.C
@@ -1,8 +1,9 @@
 // PR c++/104846
+// PR c++/101887
 // { dg-do compile { target c++14 } }
 
 struct S {
   auto operator delete (void *) {} // { dg-error ".operator delete. must 
return type .void'" }
+  auto operator delete (void*, __SIZE_TYPE__); // { dg-error ".operator 
delete. must return type .void'" }
   auto operator delete[] (void *) {} // { dg-error ".operator delete. must 
return type .void'" }
 };
-


[gcc r15-5110] c++: Fix another crash with invalid new operators [PR117463]

2024-11-11 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:f32e7339871beec0e4d49698f7e34d77ee882088

commit r15-5110-gf32e7339871beec0e4d49698f7e34d77ee882088
Author: Simon Martin 
Date:   Mon Nov 11 20:22:32 2024 +0100

c++: Fix another crash with invalid new operators [PR117463]

Even though this PR is very close to PR117101, it's not addressed by the
fix I made through r15-4958-g5821f5c8c89a05 because cxx_placement_new_fn
has the very same issue as std_placement_new_fn_p used to have.

As suggested by Jason, this patch changes both functions so that
cxx_placement_new_fn leverages std_placement_new_fn_p which reduces code
duplication and fixes the PR.

PR c++/117463

gcc/cp/ChangeLog:

* constexpr.cc (cxx_placement_new_fn): Implement in terms of
std_placement_new_fn_p.
* cp-tree.h (std_placement_new_fn_p): Declare.
* init.cc (std_placement_new_fn_p): Add missing checks to ensure
that fndecl is a non-replaceable ::operator new.

gcc/testsuite/ChangeLog:

* g++.dg/init/new54.C: New test.

Diff:
---
 gcc/cp/constexpr.cc   | 13 +
 gcc/cp/cp-tree.h  |  1 +
 gcc/cp/init.cc|  6 --
 gcc/testsuite/g++.dg/init/new54.C | 14 ++
 4 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 71e6dc4ef326..c097860e6551 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -2327,18 +2327,7 @@ cxx_replaceable_global_alloc_fn (tree fndecl)
 static inline bool
 cxx_placement_new_fn (tree fndecl)
 {
-  if (cxx_dialect >= cxx20
-  && IDENTIFIER_NEW_OP_P (DECL_NAME (fndecl))
-  && CP_DECL_CONTEXT (fndecl) == global_namespace
-  && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
-  && TREE_CODE (TREE_TYPE (fndecl)) == FUNCTION_TYPE)
-{
-  tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
-  if (TREE_VALUE (first_arg) == ptr_type_node
- && TREE_CHAIN (first_arg) == void_list_node)
-   return true;
-}
-  return false;
+  return (cxx_dialect >= cxx20 && std_placement_new_fn_p (fndecl));
 }
 
 /* Return true if FNDECL is std::construct_at.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1a0d5349749d..b3c909b05c41 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7281,6 +7281,7 @@ extern tree build_offset_ref  (tree, 
tree, bool,
 extern tree throw_bad_array_new_length (void);
 extern bool type_has_new_extended_alignment(tree);
 extern unsigned malloc_alignment   (void);
+extern bool std_placement_new_fn_p (tree);
 extern tree build_new_constexpr_heap_type  (tree, tree, tree);
 extern tree build_new  (location_t,
 vec **, tree,
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 62b3d6f6ce91..a11701002c8d 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -2976,10 +2976,12 @@ malloc_alignment ()
 
 /* Determine whether an allocation function is a namespace-scope
non-replaceable placement new function. See DR 1748.  */
-static bool
+bool
 std_placement_new_fn_p (tree alloc_fn)
 {
-  if (DECL_NAMESPACE_SCOPE_P (alloc_fn))
+  if (DECL_NAMESPACE_SCOPE_P (alloc_fn)
+  && IDENTIFIER_NEW_OP_P (DECL_NAME (alloc_fn))
+  && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (alloc_fn))
 {
   tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
   if (first_arg
diff --git a/gcc/testsuite/g++.dg/init/new54.C 
b/gcc/testsuite/g++.dg/init/new54.C
new file mode 100644
index ..fdff1b55f0d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new54.C
@@ -0,0 +1,14 @@
+// PR c++/117463
+// { dg-do "compile" { target c++20 } }
+
+struct S {};
+void *operator new[] (unsigned long, // { dg-bogus "first parameter" "" { 
xfail *-*-* } }
+ void void *volatile p); // { dg-error "two or more" }
+S *fun(void *p) {
+  return new(p) S[10];
+}
+
+void *operator new (decltype(sizeof(0)), // { dg-bogus "first parameter" "" { 
xfail *-*-* } }
+   void void * p); // { dg-error "two or more" }
+void *p;
+auto t = new(p) int;


[gcc r15-3796] c++: Don't ICE due to artificial constructor parameters [PR116722]

2024-09-23 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:d7bf5e53887a467b8c5c8439e5aae3ad4e11e62e

commit r15-3796-gd7bf5e53887a467b8c5c8439e5aae3ad4e11e62e
Author: Simon Martin 
Date:   Wed Sep 18 12:35:27 2024 +0200

c++: Don't ICE due to artificial constructor parameters [PR116722]

The following code triggers an ICE

=== cut here ===
class base {};
class derived : virtual public base {
public:
  template constexpr derived(Arg) {}
};
int main() {
  derived obj(1.);
}
=== cut here ===

The problem is that cxx_bind_parameters_in_call ends up attempting to
convert a REAL_CST (the first non artificial parameter) to INTEGER_TYPE
(the type of the __in_chrg parameter), which ICEs.

This patch changes cxx_bind_parameters_in_call to return early if it's
called with a *structor that has an __in_chrg or __vtt_parm parameter
since the expression won't be a constant expression.

Note that in the test case, the constructor is not constexpr-suitable,
however it's OK since it's a template according to my read of paragraph
(3) of [dcl.constexpr].

PR c++/116722

gcc/cp/ChangeLog:

* constexpr.cc (cxx_bind_parameters_in_call): Leave early for
{con,de}structors of classes with virtual bases.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/constexpr.cc   | 11 ++-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C | 15 +++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f6fd059be466..5c6696740fc9 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1862,6 +1862,15 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, 
tree t, tree fun,
   int nparms = list_length (parms);
   int nbinds = nargs < nparms ? nargs : nparms;
   tree binds = make_tree_vec (nbinds);
+
+  /* The call is not a constant expression if it involves the cdtor for a type
+ with virtual bases.  */
+  if (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun))
+{
+  *non_constant_p = true;
+  return binds;
+}
+
   for (i = 0; i < nargs; ++i)
 {
   tree x, arg;
@@ -1871,7 +1880,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, 
tree t, tree fun,
   x = get_nth_callarg (t, i);
   /* For member function, the first argument is a pointer to the implied
  object.  For a constructor, it might still be a dummy object, in
- which case we get the real argument from ctx. */
+which case we get the real argument from ctx.  */
   if (i == 0 && DECL_CONSTRUCTOR_P (fun)
  && is_dummy_object (x))
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
new file mode 100644
index ..279f6ec44547
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
@@ -0,0 +1,15 @@
+// PR c++/116722
+// We're now accepting this in spite of the virtual base class. This is OK
+// according to [dcl.constexpr] 3: "Except for instantiated constexpr functions
+// non-templated constexpr functions shall be constexpr-suitable".
+// { dg-do compile { target c++11 } }
+
+class base {};
+class derived : virtual public base {
+public:
+  template
+  constexpr derived(Arg) {}
+};
+int main() {
+  derived obj(1.);
+}


[gcc r15-3797] c++: Don't crash when mangling member with anonymous union or template type [PR100632, PR109790]

2024-09-23 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:a030fcad4f9f490a08db0a4cad4c22635a0585c1

commit r15-3797-ga030fcad4f9f490a08db0a4cad4c22635a0585c1
Author: Simon Martin 
Date:   Mon Sep 16 13:45:32 2024 +0200

c++: Don't crash when mangling member with anonymous union or template type 
[PR100632, PR109790]

We currently crash upon mangling members that have an anonymous union or
a template operator type.

The problem is that before calling write_unqualified_name,
write_member_name asserts that it has a declaration whose DECL_NAME is
an identifier node that is not that of an operator. This is wrong:
 - In PR100632, it's an anonymous union declaration, hence a 0 DECL_NAME
 - In PR109790, it's a legitimate template declaration for an operator
   (this was accepted up to GCC 10)

This assert was added via r11-6301, to be sure that we do write the "on"
marker for operator members.

This patch removes that assert and instead
 - Lets members with an anonymous union type go through
 - For operators, adds the missing "on" marker for ABI versions greater
   than the highest usable with GCC 10

PR c++/109790
PR c++/100632

gcc/cp/ChangeLog:

* mangle.cc (write_member_name): Handle members whose type is an
anonymous union member. Write missing "on" marker for operators
when ABI version is at least 16.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/decltype83.C: New test.
* g++.dg/cpp0x/decltype83a.C: New test.
* g++.dg/cpp1y/lambda-ice3.C: New test.
* g++.dg/cpp1y/lambda-ice3a.C: New test.
* g++.dg/cpp2a/nontype-class67.C: New test.

Diff:
---
 gcc/cp/mangle.cc |  8 +++-
 gcc/testsuite/g++.dg/cpp0x/decltype83.C  | 20 
 gcc/testsuite/g++.dg/cpp0x/decltype83a.C | 18 ++
 gcc/testsuite/g++.dg/cpp1y/lambda-ice3.C | 19 +++
 gcc/testsuite/g++.dg/cpp1y/lambda-ice3a.C| 17 +
 gcc/testsuite/g++.dg/cpp2a/nontype-class67.C |  9 +
 6 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 46dc6923adde..17988d69e1ea 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -3255,7 +3255,13 @@ write_member_name (tree member)
 }
   else if (DECL_P (member))
 {
-  gcc_assert (!DECL_OVERLOADED_OPERATOR_P (member));
+  if (ANON_AGGR_TYPE_P (TREE_TYPE (member)))
+   ;
+  else if (DECL_OVERLOADED_OPERATOR_P (member))
+   {
+ if (abi_check (16))
+   write_string ("on");
+   }
   write_unqualified_name (member);
 }
   else if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype83.C 
b/gcc/testsuite/g++.dg/cpp0x/decltype83.C
new file mode 100644
index ..b71a302d5ebb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype83.C
@@ -0,0 +1,20 @@
+// PR c++/109790
+// This used to work until GCC 10; force the usage of ABI 15 (the highest
+// usable in GCC 10) and check that the mangling (actually wrong; see
+// decltyp83a.C) matches that of GCC 10's default ABI version (14).
+
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fabi-version=15" }
+
+struct A {
+  template void operator+(T);
+};
+
+template
+decltype(&A::operator+) f();
+
+int main() {
+  f();
+}
+
+// { dg-final { scan-assembler "_Z1fIiEDTadsr1AplIT_EEv" } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype83a.C 
b/gcc/testsuite/g++.dg/cpp0x/decltype83a.C
new file mode 100644
index ..27c363651f13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype83a.C
@@ -0,0 +1,18 @@
+// PR c++/109790
+// Up to GCC 10, the mangling would be missing the "on" marker, hence be wrong.
+// Check that this is fixed with the latest ABI.
+
+// { dg-do compile { target c++11 } }
+
+struct A {
+  template void operator+(T);
+};
+
+template
+decltype(&A::operator+) f();
+
+int main() {
+  f();
+}
+
+// { dg-final { scan-assembler "_Z1fIiEDTadsr1AonplIT_EEv" } } 
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-ice3.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-ice3.C
new file mode 100644
index ..b6a2056724fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-ice3.C
@@ -0,0 +1,19 @@
+// PR c++/109790
+// This used to work until GCC 10; force the usage of ABI 15 (the highest
+// usable in GCC 10) and check that the mangling (actually wrong; see
+// lambda-ice3a.C) matches that of GCC 10's default ABI version (14).
+
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-fabi-version=15" }
+
+auto ll = [](auto ... ){};
+template 
+  void mm(void (_Impl::*__p)(_Args) const);
+template 
+using __impl_for = decltype(mm(&decltype(ll)::operator()<_Ts>));
+template  __impl_for<_Ts> f() { }
+void aaa() {
+  f();
+}
+
+// { dg-final { scan-assembler "_Z1fIiEDTcl2mmadsrN2llMUlDpT_E_EclIT_EEEv" } }
diff --git 

[gcc r15-4026] c++: Fix regression introduced by r15-3796 [PR116722]

2024-10-02 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:3a528386571fffbb41703a238aee950043af3f3c

commit r15-4026-g3a528386571fffbb41703a238aee950043af3f3c
Author: Simon Martin 
Date:   Wed Oct 2 15:32:37 2024 +0200

c++: Fix regression introduced by r15-3796 [PR116722]

Jason pointed out that the fix I made for PR116722 via r15-3796
introduces a regression when running constexpr-dynamic10.C with
-fimplicit-constexpr.

The problem is that my change makes us leave cxx_eval_call_expression
early, and bypass the call to cxx_eval_thunk_call (through a recursive
call to cxx_eval_call_expression) that used to emit an error for that
testcase with -fimplicit-constexpr.

This patch emits the error if !ctx->quiet before bailing out because the
{con,de}structor belongs to a class with virtual bases.

PR c++/116722

gcc/cp/ChangeLog:

* constexpr.cc (cxx_bind_parameters_in_call): When !ctx->quiet,
emit error before bailing out due to a call to {con,de}structor
for a class with virtual bases.

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

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 5c6696740fc9..4e4df94f4206 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1867,6 +1867,12 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, 
tree t, tree fun,
  with virtual bases.  */
   if (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun))
 {
+  if (!ctx->quiet)
+   {
+ error_at (cp_expr_loc_or_input_loc (t),
+   "call to non-% function %qD", fun);
+ explain_invalid_constexpr_fn (fun);
+   }
   *non_constant_p = true;
   return binds;
 }


[gcc r14-10892] c++: Defer -fstrong-eval-order processing to template instantiation time [PR117158]

2024-11-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:951daf54174b88e30feaf413a4de0c8388a06d9d

commit r14-10892-g951daf54174b88e30feaf413a4de0c8388a06d9d
Author: Simon Martin 
Date:   Wed Nov 6 06:54:57 2024 +0100

c++: Defer -fstrong-eval-order processing to template instantiation time 
[PR117158]

Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template  struct Sub : public Base {
  bool Get(int i) {
return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR. We do so at
template declaration time, and end up calling contains_placeholder_p
with a SCOPE_REF, that it does not handle well.

This patch fixes this by deferring the wrapping into SAVE_EXPR to
instantiation time for templates, when the SCOPE_REF will have been
turned into a COMPONENT_REF.

PR c++/117158

gcc/cp/ChangeLog:

* typeck.cc (cp_build_array_ref): Only wrap array expression
into a SAVE_EXPR at template instantiation time.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/eval-order13.C: New test.
* g++.dg/parse/crash77.C: New test.

(cherry picked from commit b1d92aeb8583c8d1491c97703680c5fb88ed1fe4)

Diff:
---
 gcc/cp/typeck.cc  |  3 ++-
 gcc/testsuite/g++.dg/cpp1z/eval-order13.C | 29 +
 gcc/testsuite/g++.dg/parse/crash77.C  | 13 +
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index a72599bc1536..6ca2cee682c4 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4073,7 +4073,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 tree ar = cp_default_conversion (array, complain);
 tree ind = cp_default_conversion (idx, complain);
 
-if (!first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+if (!processing_template_decl
+   && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
   ar = first = save_expr (ar);
 
 /* Put the integer in IND to simplify error checking.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order13.C 
b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
new file mode 100644
index ..6e8ebeb30967
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
@@ -0,0 +1,29 @@
+// PR c++/117158 - Similar to eval-order7.C, only with templates.
+// { dg-do run { target c++11 } }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b[4] = { 5, 6, 7, 8 };
+
+struct Base {
+  int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  int Get(int i) {
+Base::intarray = a;
+int r = Base::intarray[(Base::intarray = b, i)];
+if (Base::intarray != b)
+  __builtin_abort ();
+return r;
+  }
+};
+
+int
+main ()
+{
+  Sub s;
+  if (s.Get (3) != 4)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash77.C 
b/gcc/testsuite/g++.dg/parse/crash77.C
new file mode 100644
index ..729362eb5991
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash77.C
@@ -0,0 +1,13 @@
+// PR c++/117158
+// { dg-do "compile" }
+
+struct Base {
+  unsigned int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  bool Get(int i) {
+return (Base::intarray[++i] == 0);
+  }
+};


[gcc r13-9173] c++: Defer -fstrong-eval-order processing to template instantiation time [PR117158]

2024-11-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:75a5bc8c0143e7003ac19395317cc93b9a63c7d4

commit r13-9173-g75a5bc8c0143e7003ac19395317cc93b9a63c7d4
Author: Simon Martin 
Date:   Wed Nov 6 06:49:57 2024 +0100

c++: Defer -fstrong-eval-order processing to template instantiation time 
[PR117158]

Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template  struct Sub : public Base {
  bool Get(int i) {
return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR. We do so at
template declaration time, and end up calling contains_placeholder_p
with a SCOPE_REF, that it does not handle well.

This patch fixes this by deferring the wrapping into SAVE_EXPR to
instantiation time for templates, when the SCOPE_REF will have been
turned into a COMPONENT_REF.

PR c++/117158

gcc/cp/ChangeLog:

* typeck.cc (cp_build_array_ref): Only wrap array expression
into a SAVE_EXPR at template instantiation time.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/eval-order13.C: New test.
* g++.dg/parse/crash77.C: New test.

(cherry picked from commit b1d92aeb8583c8d1491c97703680c5fb88ed1fe4)

Diff:
---
 gcc/cp/typeck.cc  |  3 ++-
 gcc/testsuite/g++.dg/cpp1z/eval-order13.C | 29 +
 gcc/testsuite/g++.dg/parse/crash77.C  | 13 +
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 2b29bdc4d70a..cbd8068c3a2a 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4076,7 +4076,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 tree ar = cp_default_conversion (array, complain);
 tree ind = cp_default_conversion (idx, complain);
 
-if (!first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+if (!processing_template_decl
+   && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
   ar = first = save_expr (ar);
 
 /* Put the integer in IND to simplify error checking.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order13.C 
b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
new file mode 100644
index ..6e8ebeb30967
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
@@ -0,0 +1,29 @@
+// PR c++/117158 - Similar to eval-order7.C, only with templates.
+// { dg-do run { target c++11 } }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b[4] = { 5, 6, 7, 8 };
+
+struct Base {
+  int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  int Get(int i) {
+Base::intarray = a;
+int r = Base::intarray[(Base::intarray = b, i)];
+if (Base::intarray != b)
+  __builtin_abort ();
+return r;
+  }
+};
+
+int
+main ()
+{
+  Sub s;
+  if (s.Get (3) != 4)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash77.C 
b/gcc/testsuite/g++.dg/parse/crash77.C
new file mode 100644
index ..729362eb5991
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash77.C
@@ -0,0 +1,13 @@
+// PR c++/117158
+// { dg-do "compile" }
+
+struct Base {
+  unsigned int *intarray;
+};
+
+template 
+struct Sub : public Base {
+  bool Get(int i) {
+return (Base::intarray[++i] == 0);
+  }
+};


[gcc r12-10847] c++: Don't reject pointer to virtual method during constant evaluation [PR117615]

2024-12-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:ae8d9d2b40aa7fd6a455beda38ff1b3c21728c31

commit r12-10847-gae8d9d2b40aa7fd6a455beda38ff1b3c21728c31
Author: Simon Martin 
Date:   Tue Dec 3 14:30:43 2024 +0100

c++: Don't reject pointer to virtual method during constant evaluation 
[PR117615]

We currently reject the following valid code:

=== cut here ===
struct Base {
virtual void doit (int v) const {}
};
struct Derived : Base {
void doit (int v) const {}
};
using fn_t = void (Base::*)(int) const;
struct Helper {
fn_t mFn;
constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
};
void foo () {
constexpr Helper h (&Derived::doit);
}
=== cut here ===

The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
represented with an expression with type pointer to method and using an
INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects any
such expression with a non-null INTEGER_CST.

This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix for
PR c++/102786), and simply lets such expressions go through.

PR c++/117615

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_constant_expression): Don't reject
INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-virtual22.C: New test.

(cherry picked from commit 72a2380a306a1c3883cb7e4f99253522bc265af0)

Diff:
---
 gcc/cp/constexpr.cc  |  6 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C | 22 ++
 2 files changed, 28 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 20abbee3600e..6c8d8ab17f29 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7353,6 +7353,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
return t;
  }
  }
+   else if (TYPE_PTR_P (type)
+   && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ /* INTEGER_CST with pointer-to-method type is only used
+for a virtual method in a pointer to member function.
+Don't reject those.  */
+ ;
else
  {
/* This detects for example:
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
new file mode 100644
index ..89330bf86200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
@@ -0,0 +1,22 @@
+// PR c++/117615
+// { dg-do "compile" { target c++20 } }
+
+struct Base {
+virtual void doit (int v) const {}
+};
+
+struct Derived : Base {
+void doit (int v) const {}
+};
+
+using fn_t = void (Base::*)(int) const;
+
+struct Helper {
+fn_t mFn;
+constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
+};
+
+void foo () {
+constexpr Helper h (&Derived::doit);
+constexpr Helper h2 (&Base::doit);
+}


[gcc r15-5920] c++: Don't reject pointer to virtual method during constant evaluation [PR117615]

2024-12-04 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:72a2380a306a1c3883cb7e4f99253522bc265af0

commit r15-5920-g72a2380a306a1c3883cb7e4f99253522bc265af0
Author: Simon Martin 
Date:   Tue Dec 3 14:30:43 2024 +0100

c++: Don't reject pointer to virtual method during constant evaluation 
[PR117615]

We currently reject the following valid code:

=== cut here ===
struct Base {
virtual void doit (int v) const {}
};
struct Derived : Base {
void doit (int v) const {}
};
using fn_t = void (Base::*)(int) const;
struct Helper {
fn_t mFn;
constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
};
void foo () {
constexpr Helper h (&Derived::doit);
}
=== cut here ===

The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
represented with an expression with type pointer to method and using an
INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects any
such expression with a non-null INTEGER_CST.

This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix for
PR c++/102786), and simply lets such expressions go through.

PR c++/117615

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_constant_expression): Don't reject
INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-virtual22.C: New test.

Diff:
---
 gcc/cp/constexpr.cc  |  6 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C | 22 ++
 2 files changed, 28 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 5a87fa485c61..c1d540133d5e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8275,6 +8275,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
return t;
  }
  }
+   else if (TYPE_PTR_P (type)
+   && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ /* INTEGER_CST with pointer-to-method type is only used
+for a virtual method in a pointer to member function.
+Don't reject those.  */
+ ;
else
  {
/* This detects for example:
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
new file mode 100644
index ..89330bf86200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
@@ -0,0 +1,22 @@
+// PR c++/117615
+// { dg-do "compile" { target c++20 } }
+
+struct Base {
+virtual void doit (int v) const {}
+};
+
+struct Derived : Base {
+void doit (int v) const {}
+};
+
+using fn_t = void (Base::*)(int) const;
+
+struct Helper {
+fn_t mFn;
+constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
+};
+
+void foo () {
+constexpr Helper h (&Derived::doit);
+constexpr Helper h2 (&Base::doit);
+}


[gcc r13-9230] c++: Don't reject pointer to virtual method during constant evaluation [PR117615]

2024-12-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:322faea202947561ee8c03edf5ab0ccf649587e1

commit r13-9230-g322faea202947561ee8c03edf5ab0ccf649587e1
Author: Simon Martin 
Date:   Tue Dec 3 14:30:43 2024 +0100

c++: Don't reject pointer to virtual method during constant evaluation 
[PR117615]

We currently reject the following valid code:

=== cut here ===
struct Base {
virtual void doit (int v) const {}
};
struct Derived : Base {
void doit (int v) const {}
};
using fn_t = void (Base::*)(int) const;
struct Helper {
fn_t mFn;
constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
};
void foo () {
constexpr Helper h (&Derived::doit);
}
=== cut here ===

The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
represented with an expression with type pointer to method and using an
INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects any
such expression with a non-null INTEGER_CST.

This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix for
PR c++/102786), and simply lets such expressions go through.

PR c++/117615

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_constant_expression): Don't reject
INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-virtual22.C: New test.

(cherry picked from commit 72a2380a306a1c3883cb7e4f99253522bc265af0)

Diff:
---
 gcc/cp/constexpr.cc  |  6 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C | 22 ++
 2 files changed, 28 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fb8a1023b222..f885a806c0a2 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7778,6 +7778,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
return t;
  }
  }
+   else if (TYPE_PTR_P (type)
+   && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ /* INTEGER_CST with pointer-to-method type is only used
+for a virtual method in a pointer to member function.
+Don't reject those.  */
+ ;
else
  {
/* This detects for example:
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
new file mode 100644
index ..89330bf86200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
@@ -0,0 +1,22 @@
+// PR c++/117615
+// { dg-do "compile" { target c++20 } }
+
+struct Base {
+virtual void doit (int v) const {}
+};
+
+struct Derived : Base {
+void doit (int v) const {}
+};
+
+using fn_t = void (Base::*)(int) const;
+
+struct Helper {
+fn_t mFn;
+constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
+};
+
+void foo () {
+constexpr Helper h (&Derived::doit);
+constexpr Helper h2 (&Base::doit);
+}


[gcc r14-11063] c++: Don't reject pointer to virtual method during constant evaluation [PR117615]

2024-12-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:4a73efcbdc5fb9c3f6ab0cba718dd25b5062fc22

commit r14-11063-g4a73efcbdc5fb9c3f6ab0cba718dd25b5062fc22
Author: Simon Martin 
Date:   Tue Dec 3 14:30:43 2024 +0100

c++: Don't reject pointer to virtual method during constant evaluation 
[PR117615]

We currently reject the following valid code:

=== cut here ===
struct Base {
virtual void doit (int v) const {}
};
struct Derived : Base {
void doit (int v) const {}
};
using fn_t = void (Base::*)(int) const;
struct Helper {
fn_t mFn;
constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
};
void foo () {
constexpr Helper h (&Derived::doit);
}
=== cut here ===

The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
represented with an expression with type pointer to method and using an
INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects any
such expression with a non-null INTEGER_CST.

This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix for
PR c++/102786), and simply lets such expressions go through.

PR c++/117615

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_constant_expression): Don't reject
INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-virtual22.C: New test.

(cherry picked from commit 72a2380a306a1c3883cb7e4f99253522bc265af0)

Diff:
---
 gcc/cp/constexpr.cc  |  6 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C | 22 ++
 2 files changed, 28 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 853694d78a56..40cc755258ff 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8254,6 +8254,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
return t;
  }
  }
+   else if (TYPE_PTR_P (type)
+   && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ /* INTEGER_CST with pointer-to-method type is only used
+for a virtual method in a pointer to member function.
+Don't reject those.  */
+ ;
else
  {
/* This detects for example:
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
new file mode 100644
index ..89330bf86200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
@@ -0,0 +1,22 @@
+// PR c++/117615
+// { dg-do "compile" { target c++20 } }
+
+struct Base {
+virtual void doit (int v) const {}
+};
+
+struct Derived : Base {
+void doit (int v) const {}
+};
+
+using fn_t = void (Base::*)(int) const;
+
+struct Helper {
+fn_t mFn;
+constexpr Helper (auto && fn) : mFn(static_cast(fn)) {}
+};
+
+void foo () {
+constexpr Helper h (&Derived::doit);
+constexpr Helper h2 (&Base::doit);
+}


[gcc r15-6022] tree-eh: Don't crash on GIMPLE_TRY_FINALLY with empty cleanup sequence [PR117845]

2024-12-09 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:3076539544d3e36684cc8eed3374aeff5b44c9b1

commit r15-6022-g3076539544d3e36684cc8eed3374aeff5b44c9b1
Author: Simon Martin 
Date:   Mon Dec 9 09:21:25 2024 +0100

tree-eh: Don't crash on GIMPLE_TRY_FINALLY with empty cleanup sequence 
[PR117845]

The following valid code triggers an ICE with -fsanitize=address

=== cut here ===
void l() {
auto const ints = {0,1,2,3,4,5};
for (auto i : { 3 } ) {
__builtin_printf("%d ", i);
}
}
=== cut here ===

The problem is that honor_protect_cleanup_actions does not expect the
cleanup sequence of a GIMPLE_TRY_FINALLY to be empty. It is however the
case here since r14-8681-gceb242f5302027, because lower_stmt removes the
only statement in the sequence: a ASAN_MARK statement for the array that
backs the initializer_list).

This patch simply checks that the finally block is not 0 before
accessing it in honor_protect_cleanup_actions.

PR c++/117845

gcc/ChangeLog:

* tree-eh.cc (honor_protect_cleanup_actions): Support empty
finally sequences.

gcc/testsuite/ChangeLog:

* g++.dg/asan/pr117845-2.C: New test.
* g++.dg/asan/pr117845.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/asan/pr117845-2.C | 12 
 gcc/testsuite/g++.dg/asan/pr117845.C   | 12 
 gcc/tree-eh.cc |  5 +++--
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/asan/pr117845-2.C 
b/gcc/testsuite/g++.dg/asan/pr117845-2.C
new file mode 100644
index ..c05563970091
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr117845-2.C
@@ -0,0 +1,12 @@
+// PR c++/117845 - Actually valid variant
+// { dg-do "compile" }
+// { dg-options "-fsanitize=address" }
+
+#include 
+
+void l() {
+auto const ints = {0,1,2,3,4,5};
+for (auto i : { 3 } ) {
+__builtin_printf("%d ", i);
+}
+}
diff --git a/gcc/testsuite/g++.dg/asan/pr117845.C 
b/gcc/testsuite/g++.dg/asan/pr117845.C
new file mode 100644
index ..d90d351e2701
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr117845.C
@@ -0,0 +1,12 @@
+// PR c++/117845 - Initially reported case.
+// { dg-do "compile" }
+// { dg-options "-fsanitize=address" }
+
+#include 
+
+void l() {
+auto const ints = {0,1,2,3,4,5};
+for (int i : ints | h) { // { dg-error "was not declared" }
+__builtin_printf("%d ", i);
+}
+}
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index 769785fad2b9..e8af5fb8989b 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -1025,8 +1025,9 @@ honor_protect_cleanup_actions (struct leh_state 
*outer_state,
 terminate before we get to it, so strip it away before adding the
 MUST_NOT_THROW filter.  */
   gimple_stmt_iterator gsi = gsi_start (finally);
-  gimple *x = gsi_stmt (gsi);
-  if (gimple_code (x) == GIMPLE_TRY
+  gimple *x = !gsi_end_p (gsi) ? gsi_stmt (gsi) : NULL;
+  if (x
+ && gimple_code (x) == GIMPLE_TRY
  && gimple_try_kind (x) == GIMPLE_TRY_CATCH
  && gimple_try_catch_is_cleanup (x))
{


[gcc r14-11075] tree-eh: Don't crash on GIMPLE_TRY_FINALLY with empty cleanup sequence [PR117845]

2024-12-09 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:ac054467bf42365de85336775cba9b9f476e73ed

commit r14-11075-gac054467bf42365de85336775cba9b9f476e73ed
Author: Simon Martin 
Date:   Mon Dec 9 09:21:25 2024 +0100

tree-eh: Don't crash on GIMPLE_TRY_FINALLY with empty cleanup sequence 
[PR117845]

The following valid code triggers an ICE with -fsanitize=address

=== cut here ===
void l() {
auto const ints = {0,1,2,3,4,5};
for (auto i : { 3 } ) {
__builtin_printf("%d ", i);
}
}
=== cut here ===

The problem is that honor_protect_cleanup_actions does not expect the
cleanup sequence of a GIMPLE_TRY_FINALLY to be empty. It is however the
case here since r14-8681-gceb242f5302027, because lower_stmt removes the
only statement in the sequence: a ASAN_MARK statement for the array that
backs the initializer_list).

This patch simply checks that the finally block is not 0 before
accessing it in honor_protect_cleanup_actions.

PR c++/117845

gcc/ChangeLog:

* tree-eh.cc (honor_protect_cleanup_actions): Support empty
finally sequences.

gcc/testsuite/ChangeLog:

* g++.dg/asan/pr117845-2.C: New test.
* g++.dg/asan/pr117845.C: New test.

(cherry picked from commit 3076539544d3e36684cc8eed3374aeff5b44c9b1)

Diff:
---
 gcc/testsuite/g++.dg/asan/pr117845-2.C | 12 
 gcc/testsuite/g++.dg/asan/pr117845.C   | 12 
 gcc/tree-eh.cc |  5 +++--
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/asan/pr117845-2.C 
b/gcc/testsuite/g++.dg/asan/pr117845-2.C
new file mode 100644
index ..c05563970091
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr117845-2.C
@@ -0,0 +1,12 @@
+// PR c++/117845 - Actually valid variant
+// { dg-do "compile" }
+// { dg-options "-fsanitize=address" }
+
+#include 
+
+void l() {
+auto const ints = {0,1,2,3,4,5};
+for (auto i : { 3 } ) {
+__builtin_printf("%d ", i);
+}
+}
diff --git a/gcc/testsuite/g++.dg/asan/pr117845.C 
b/gcc/testsuite/g++.dg/asan/pr117845.C
new file mode 100644
index ..d90d351e2701
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr117845.C
@@ -0,0 +1,12 @@
+// PR c++/117845 - Initially reported case.
+// { dg-do "compile" }
+// { dg-options "-fsanitize=address" }
+
+#include 
+
+void l() {
+auto const ints = {0,1,2,3,4,5};
+for (int i : ints | h) { // { dg-error "was not declared" }
+__builtin_printf("%d ", i);
+}
+}
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index 199b6d5d0051..a8de341e562a 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -1025,8 +1025,9 @@ honor_protect_cleanup_actions (struct leh_state 
*outer_state,
 terminate before we get to it, so strip it away before adding the
 MUST_NOT_THROW filter.  */
   gimple_stmt_iterator gsi = gsi_start (finally);
-  gimple *x = gsi_stmt (gsi);
-  if (gimple_code (x) == GIMPLE_TRY
+  gimple *x = !gsi_end_p (gsi) ? gsi_stmt (gsi) : NULL;
+  if (x
+ && gimple_code (x) == GIMPLE_TRY
  && gimple_try_kind (x) == GIMPLE_TRY_CATCH
  && gimple_try_catch_is_cleanup (x))
{


[gcc r15-7348] c++: Properly detect calls to digest_init in build_vec_init [PR114619]

2025-02-04 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:887bdabfe3e315d661bed55800cd4f64542c7029

commit r15-7348-g887bdabfe3e315d661bed55800cd4f64542c7029
Author: Simon Martin 
Date:   Tue Feb 4 10:44:10 2025 +0100

c++: Properly detect calls to digest_init in build_vec_init [PR114619]

We currently ICE in checking mode with cxx_dialect < 17 on the following
valid code

=== cut here ===
struct X {
  X(const X&) {}
};
extern X x;
void foo () {
  new X[1]{x};
}
=== cut here ===

We trip on a gcc_checking_assert in cp_gimplify_expr due to a
TARGET_EXPR that is not TARGET_EXPR_ELIDING_P. As pointed by Jason, the
problem is that build_vec_init does not recognize that digest_init has
been called, and we end up calling the copy constructor twice.

This happens because the detection in build_vec_init assumes that BASE
is a reference to the array, while it's a pointer to its first element
here. This patch makes sure that the detection works in both cases.

PR c++/114619

gcc/cp/ChangeLog:

* init.cc (build_vec_init): Properly determine whether
digest_init has been called.

gcc/testsuite/ChangeLog:

* g++.dg/init/no-elide4.C: New test.

Diff:
---
 gcc/cp/init.cc|  3 ++-
 gcc/testsuite/g++.dg/init/no-elide4.C | 11 +++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 3ab7f96335c9..613775c5a7c8 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4786,7 +4786,8 @@ build_vec_init (tree base, tree maxindex, tree init,
   tree field, elt;
   /* If the constructor already has the array type, it's been through
 digest_init, so we shouldn't try to do anything more.  */
-  bool digested = same_type_p (atype, TREE_TYPE (init));
+  bool digested = (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
+  && same_type_p (type, TREE_TYPE (TREE_TYPE (init;
   from_array = 0;
 
   if (length_check)
diff --git a/gcc/testsuite/g++.dg/init/no-elide4.C 
b/gcc/testsuite/g++.dg/init/no-elide4.C
new file mode 100644
index ..9377d9f01611
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/no-elide4.C
@@ -0,0 +1,11 @@
+// PR c++/114619
+// { dg-do "compile" { target c++11 } }
+// { dg-options "-fno-elide-constructors" }
+
+struct X {
+  X(const X&) {}
+};
+extern X x;
+void foo () {
+  new X[1]{x};
+}


[gcc r15-7350] c++: Fix overeager Woverloaded-virtual with conversion operators [PR109918]

2025-02-04 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:d346af2af88caf1e21a5cc1f0afa33596198fb60

commit r15-7350-gd346af2af88caf1e21a5cc1f0afa33596198fb60
Author: Simon Martin 
Date:   Tue Feb 4 10:58:17 2025 +0100

c++: Fix overeager Woverloaded-virtual with conversion operators [PR109918]

We currently emit an incorrect -Woverloaded-virtual warning upon the
following test case

=== cut here ===
struct A {
  virtual operator int() { return 42; }
  virtual operator char() = 0;
};
struct B : public A {
  operator char() { return 'A'; }
};
=== cut here ===

The problem is that when iterating over ovl_range (fns), warn_hidden
gets confused by the conversion operator marker, concludes that
seen_non_override is true and therefore emits a warning for all
conversion operators in A that do not convert to char, even if
-Woverloaded-virtual is 1 (e.g. with -Wall, the case reported).

A second set of problems is highlighted when -Woverloaded-virtual is 2.

First, with the same test case, since base_fndecls contains all
conversion operators in A (except the one to char, that's been removed
when iterating over ovl_range (fns)), we emit a spurious warning for
the conversion operator to int, even though it's unrelated.

Second, in case there are several conversion operators with different
cv-qualifiers to the same type in A, we rightfully emit a warning,
however the note uses the location of the conversion operator marker
instead of the right one; location_of should go over conv_op_marker.

This patch fixes all these by explicitly keeping track of (1) base
methods that are overriden, as well as (2) base methods that are hidden
but not overriden (and by what), and warning about methods that are in
(2) but not (1). It also ignores non virtual base methods, per
"definition" of -Woverloaded-virtual.

Co-authored-by: Jason Merrill 

PR c++/117114
PR c++/109918

gcc/cp/ChangeLog:

* class.cc (warn_hidden): Keep track of overloaded and of hidden
base methods.
* error.cc (location_of): Skip over conv_op_marker.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Woverloaded-virt1.C: Check that no warning is
emitted for non virtual base methods.
* g++.dg/warn/Woverloaded-virt10.C: New test.
* g++.dg/warn/Woverloaded-virt11.C: New test.
* g++.dg/warn/Woverloaded-virt12.C: New test.
* g++.dg/warn/Woverloaded-virt13.C: New test.
* g++.dg/warn/Woverloaded-virt5.C: New test.
* g++.dg/warn/Woverloaded-virt6.C: New test.
* g++.dg/warn/Woverloaded-virt7.C: New test.
* g++.dg/warn/Woverloaded-virt8.C: New test.
* g++.dg/warn/Woverloaded-virt9.C: New test.

Diff:
---
 gcc/cp/class.cc| 92 --
 gcc/cp/error.cc|  3 +-
 gcc/testsuite/g++.dg/warn/Woverloaded-virt1.C  |  2 +
 gcc/testsuite/g++.dg/warn/Woverloaded-virt10.C | 11 +++
 gcc/testsuite/g++.dg/warn/Woverloaded-virt11.C | 25 +++
 gcc/testsuite/g++.dg/warn/Woverloaded-virt12.C | 23 +++
 gcc/testsuite/g++.dg/warn/Woverloaded-virt13.C | 28 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C  | 12 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt6.C  | 12 
 gcc/testsuite/g++.dg/warn/Woverloaded-virt7.C  | 37 +++
 gcc/testsuite/g++.dg/warn/Woverloaded-virt8.C  | 15 +
 gcc/testsuite/g++.dg/warn/Woverloaded-virt9.C  | 14 
 12 files changed, 239 insertions(+), 35 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 130fbc9a9724..d5ae69b0fdfa 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -3243,10 +3243,16 @@ warn_hidden (tree t)
  continue;
 
tree name = OVL_NAME (fns);
+   size_t num_fns = 0; /* The number of fndecls in fns.  */
auto_vec base_fndecls;
tree base_binfo;
tree binfo;
unsigned j;
+   size_t num_overriders = 0;
+   hash_set overriden_base_fndecls;
+   /* base_fndecls that are hidden but not overriden. The "value"
+  contains the last fndecl we saw that hides the "key".  */
+   hash_map hidden_base_fndecls;
 
if (IDENTIFIER_CDTOR_P (name))
  continue;
@@ -3264,47 +3270,65 @@ warn_hidden (tree t)
if (base_fndecls.is_empty ())
  continue;
 
-   /* Remove any overridden functions.  */
-   bool seen_non_override = false;
+   /* Find all the base_fndecls that are overridden, as well as those
+  that are hidden, in T.  */
for (tree fndecl : ovl_range (fns))
  {
-   bool any_override = false;
-   if (TREE_CODE (fndecl) == FUNCTION_DECL
-   && DECL_VINDEX (fndecl))
+   bool template_p = TREE_CODE (fndecl) == TEMPLATE_DECL;
+   bool fndecl_ove

[gcc r15-7380] c++: Reject default arguments for template class friend functions [PR118319]

2025-02-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:198f4df07d6a1db9c8ef39536da56c1b596c57a8

commit r15-7380-g198f4df07d6a1db9c8ef39536da56c1b596c57a8
Author: Simon Martin 
Date:   Wed Feb 5 20:35:34 2025 +0100

c++: Reject default arguments for template class friend functions [PR118319]

We segfault upon the following invalid code

=== cut here ===
template  struct S {
  friend void foo (int a = []{}());
};
void foo (int a) {}
int main () {
  S<0> t;
  foo ();
}
=== cut here ===

The problem is that we end up with a LAMBDA_EXPR callee in
set_flags_from_callee, and dereference its NULL_TREE
TREE_TYPE (TREE_TYPE (..)).

This patch sets the default argument to error_mark_node and gives a hard
error for template class friend functions that do not meet the
requirement in C++17 11.3.6/4 (the change is restricted to templates per
discussion with Jason).

PR c++/118319

gcc/cp/ChangeLog:

* decl.cc (grokfndecl): Inspect all friend function parameters.
If it's not valid for them to have a default value and we're
processing a template, set the default value to error_mark_node
and give a hard error.

gcc/testsuite/ChangeLog:

* g++.dg/parse/defarg18.C: New test.
* g++.dg/parse/defarg18a.C: New test.

Diff:
---
 gcc/cp/decl.cc | 22 +---
 gcc/testsuite/g++.dg/parse/defarg18.C  | 48 ++
 gcc/testsuite/g++.dg/parse/defarg18a.C | 33 +++
 3 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b7af33b32317..4238314558b1 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -11213,14 +11213,28 @@ grokfndecl (tree ctype,
  expression, that declaration shall be a definition..."  */
   if (friendp && !funcdef_flag)
 {
+  bool has_errored = false;
   for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl);
   t && t != void_list_node; t = TREE_CHAIN (t))
if (TREE_PURPOSE (t))
  {
-   permerror (DECL_SOURCE_LOCATION (decl),
-  "friend declaration of %qD specifies default "
-  "arguments and isn%'t a definition", decl);
-   break;
+   diagnostic_t diag_kind = DK_PERMERROR;
+   /* For templates, mark the default argument as erroneous and give a
+  hard error.  */
+   if (processing_template_decl)
+ {
+   diag_kind = DK_ERROR;
+   TREE_PURPOSE (t) = error_mark_node;
+ }
+   if (!has_errored)
+ {
+   has_errored = true;
+   emit_diagnostic (diag_kind,
+DECL_SOURCE_LOCATION (decl),
+/*diagnostic_option_id=*/0,
+"friend declaration of %qD specifies default "
+"arguments and isn%'t a definition", decl);
+ }
  }
 }
 
diff --git a/gcc/testsuite/g++.dg/parse/defarg18.C 
b/gcc/testsuite/g++.dg/parse/defarg18.C
new file mode 100644
index ..62c8f15f2843
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg18.C
@@ -0,0 +1,48 @@
+// PR c++/118319
+// { dg-do "compile" { target c++11 } }
+
+// Template case, that used to crash.
+
+template 
+struct S {
+  friend void foo1 (int a = []{}());  // { dg-error "specifies default|only 
declaration" }
+  friend void foo3 (int a,   // { dg-error "specifies default|only 
declaration" }
+   int b = []{}(),
+   int c = []{}());
+};
+
+void foo1 (int a) {}
+void foo3 (int a, int b, int c) {}
+
+void hello (){
+  S<0> t;
+  foo1 ();
+  foo3 (1, 2);
+}
+
+
+// Template case, that already worked.
+
+template 
+struct T {
+  friend void bar (int a = []{}()); // { dg-error "specifies default|only 
declaration" }
+};
+
+void hallo (){
+  T<0> t;
+  bar (); // { dg-error "not declared" }
+}
+
+
+// Non template case, that already worked.
+
+struct NoTemplate {
+  friend void baz (int a = []{}()); // { dg-error "specifies default|could not 
convert" }
+};
+
+void baz (int a) {} // { dg-error "only declaration" }
+
+void ola (){
+  NoTemplate t;
+  baz (); // { dg-error "void value not ignored" }
+}
diff --git a/gcc/testsuite/g++.dg/parse/defarg18a.C 
b/gcc/testsuite/g++.dg/parse/defarg18a.C
new file mode 100644
index ..9157a4d5158f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg18a.C
@@ -0,0 +1,33 @@
+// PR c++/118319 - With -fpermissive
+// { dg-do "compile" { target c++11 } }
+// { dg-additional-options "-fpermissive" }
+
+// Template case, that used to crash.
+// Check that we error-out even with -fpermissive.
+
+template 
+struct S { // { dg-error "instantiating erroneous template" }
+  friend void foo1 (int a = []{}());  // { dg-warning "specifies default|only 
declaration" }
+

[gcc r15-7416] c++: Properly support null pointer constants in conditional operators [PR118282]

2025-02-07 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:0b2f34ca19edf2b033c90ff378f561429b82a77a

commit r15-7416-g0b2f34ca19edf2b033c90ff378f561429b82a77a
Author: Simon Martin 
Date:   Fri Feb 7 15:00:14 2025 +0100

c++: Properly support null pointer constants in conditional operators 
[PR118282]

We've been rejecting the following valid code since GCC 4

=== cut here ===
struct A {
  explicit A (int);
  operator void* () const;
};
void foo (const A& x) {
  auto res = 0 ? x : 0;
}
int main () {
  A a{5};
  foo(a);
}
=== cut here ===

The problem is that for COND_EXPR, add_builtin_candidate has an early
return if the true and false values are not pointers that does not take
null pointer constants into account. This causes to not find any valid
conversion, and fail to compile.

This patch fixes the condition to also pass if the true/false values are
not pointers but null pointer constants, which resolves the PR.

PR c++/118282

gcc/cp/ChangeLog:

* call.cc (add_builtin_candidate): Also check for null_ptr_cst_p
operands.

gcc/testsuite/ChangeLog:

* g++.dg/conversion/op8.C: New test.

Diff:
---
 gcc/cp/call.cc|  3 +-
 gcc/testsuite/g++.dg/conversion/op8.C | 75 +++
 2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index c08bd0c8634a..e440d58141ba 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -3272,7 +3272,8 @@ add_builtin_candidate (struct z_candidate **candidates, 
enum tree_code code,
break;
 
   /* Otherwise, the types should be pointers.  */
-  if (!TYPE_PTR_OR_PTRMEM_P (type1) || !TYPE_PTR_OR_PTRMEM_P (type2))
+  if (!((TYPE_PTR_OR_PTRMEM_P (type1) || null_ptr_cst_p (args[0]))
+   && (TYPE_PTR_OR_PTRMEM_P (type2) || null_ptr_cst_p (args[1]
return;
 
   /* We don't check that the two types are the same; the logic
diff --git a/gcc/testsuite/g++.dg/conversion/op8.C 
b/gcc/testsuite/g++.dg/conversion/op8.C
new file mode 100644
index ..eac958776c94
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/op8.C
@@ -0,0 +1,75 @@
+// PR c++/118282
+// { dg-do "compile" }
+
+#if __cplusplus >= 201103L
+# include  // Only available from c++11 onwards.
+#endif
+
+struct A {
+  explicit A (int);
+  operator void* () const;
+};
+
+struct B {
+  explicit B (int);
+  operator char* () const;
+};
+
+struct C {
+  explicit C (int);
+  operator int () const;
+};
+
+struct BothWays {
+  BothWays (int);
+  operator void*() const;
+};
+
+extern bool my_bool;
+
+void foo (const A& a, const B& b, const C& c, const BothWays& d) {
+  void *res_a_1 = 0  ? 0 : a;
+  void *res_a_2 = 1  ? 0 : a;
+  void *res_a_3 = my_bool ? 0 : a;
+  void *res_a_4 = 0  ? a : 0;
+  void *res_a_5 = 1  ? a : 0;
+  void *res_a_6 = my_bool ? a : 0;
+
+  void *res_b_1 = 0  ? 0 : b;
+  void *res_b_2 = 1  ? 0 : b;
+  void *res_b_3 = my_bool ? 0 : b;
+  void *res_b_4 = 0  ? b : 0;
+  void *res_b_5 = 1  ? b : 0;
+  void *res_b_6 = my_bool ? b : 0;
+
+  //
+  // 0 valued constants that are NOT null pointer constants - this worked 
already.
+  //
+  char zero_char  = 0;
+  void *res_ko1  = 0 ? zero_char : a; // { dg-error "different 
types" }
+
+#if __cplusplus >= 201103L
+  // Those are only available starting with c++11.
+  int8_t zero_i8  = 0;
+  void *res_ko2  = 0 ? zero_i8   : a; // { dg-error "different 
types" "" { target c++11 }  }
+  uintptr_t zerop = 0;
+  void *res_ko3  = 0 ? zerop : a; // { dg-error "different 
types" "" { target c++11 }  }
+#endif
+
+  // Conversion to integer - this worked already.
+  int res_int= 0 ? 0 : c;
+
+  // Case where one arm is of class type that can be constructed from an
+  // integer and the other arm is a null pointer constant (inspired by
+  // g++.dg/template/cond5.C).
+  0 ? d : 0;
+  0 ? 0 : d;
+}
+
+int main(){
+  A a (5);
+  B b (42);
+  C c (43);
+  BothWays d (1982);
+  foo (a, b, c, d);
+}


[gcc r15-7475] c++: Reject cdtors and conversion operators with a single * as return type [PR118304, PR118306]

2025-02-11 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:c74e7f651a014d59631361bcc9be05d797928c5c

commit r15-7475-gc74e7f651a014d59631361bcc9be05d797928c5c
Author: Simon Martin 
Date:   Tue Feb 11 15:59:02 2025 +0100

c++: Reject cdtors and conversion operators with a single * as return type 
[PR118304, PR118306]

We currently accept the following constructor declaration (clang, EDG
and MSVC do as well), and ICE on the destructor declaration

=== cut here ===
struct A {
  *A ();
  ~A () = default;
};
=== cut here ===

The problem is that we end up in grokdeclarator with a cp_declarator of
kind cdk_pointer but no type, and we happily go through (if we have a
reference instead we eventually error out trying to form a reference to
void).

This patch makes sure that grokdeclarator errors out and strips the
invalid declarator when processing a cdtor (or a conversion operator
with no return type specified) with a declarator representing a pointer
or a reference type.

PR c++/118306
PR c++/118304

gcc/cp/ChangeLog:

* decl.cc (maybe_strip_indirect_ref): New.
(check_special_function_return_type): Take declarator as input.
Call maybe_strip_indirect_ref and error out if it returns true.
(grokdeclarator): Update call to
check_special_function_return_type.

gcc/testsuite/ChangeLog:

* g++.old-deja/g++.jason/operator.C: Adjust bogus test
expectation (char** vs char*).
* g++.dg/parse/constructor4.C: New test.
* g++.dg/parse/constructor5.C: New test.
* g++.dg/parse/conv_op2.C: New test.
* g++.dg/parse/default_to_int.C: New test.

Diff:
---
 gcc/cp/decl.cc  | 50 +--
 gcc/testsuite/g++.dg/parse/constructor4.C   | 54 +
 gcc/testsuite/g++.dg/parse/constructor5.C   | 48 ++
 gcc/testsuite/g++.dg/parse/conv_op2.C   | 10 +
 gcc/testsuite/g++.dg/parse/default_to_int.C | 37 +
 gcc/testsuite/g++.old-deja/g++.jason/operator.C |  2 +-
 6 files changed, 187 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 84abc17ade0f..552a7a2ec546 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -101,7 +101,8 @@ static void end_cleanup_fn (void);
 static tree cp_make_fname_decl (location_t, tree, int);
 static void initialize_predefined_identifiers (void);
 static tree check_special_function_return_type
-   (special_function_kind, tree, tree, int, const location_t*);
+   (special_function_kind, tree, tree, int, const cp_declarator**,
+   const location_t*);
 static tree push_cp_library_fn (enum tree_code, tree, int);
 static tree build_cp_library_fn (tree, enum tree_code, tree, int);
 static void store_parm_decls (tree);
@@ -12441,10 +12442,27 @@ smallest_type_location (const cp_decl_specifier_seq 
*declspecs)
   return smallest_type_location (type_quals, declspecs->locations);
 }
 
-/* Check that it's OK to declare a function with the indicated TYPE
-   and TYPE_QUALS.  SFK indicates the kind of special function (if any)
-   that this function is.  OPTYPE is the type given in a conversion
-   operator declaration, or the class type for a constructor/destructor.
+/* Returns whether DECLARATOR represented a pointer or a reference and if so,
+   strip out the pointer/reference declarator(s).  */
+
+static bool
+maybe_strip_indirect_ref (const cp_declarator** declarator)
+{
+  bool indirect_ref_p = false;
+  while (declarator && *declarator
+&& ((*declarator)->kind == cdk_pointer
+|| (*declarator)->kind == cdk_reference))
+{
+  indirect_ref_p = true;
+  *declarator = (*declarator)->declarator;
+}
+  return indirect_ref_p;
+}
+
+/* Check that it's OK to declare a function with the indicated TYPE, TYPE_QUALS
+   and DECLARATOR.  SFK indicates the kind of special function (if any) that
+   this function is.  OPTYPE is the type given in a conversion operator
+   declaration, or the class type for a constructor/destructor.
Returns the actual return type of the function; that may be different
than TYPE if an error occurs, or for certain special functions.  */
 
@@ -12453,13 +12471,18 @@ check_special_function_return_type 
(special_function_kind sfk,
tree type,
tree optype,
int type_quals,
+   const cp_declarator** declarator,
const location_t* locations)
 {
+  gcc_assert (declarator);
+  location_t rettype_loc = (type
+   ? smallest_type_location (type_quals, locations)
+   : (*declarator)->id_loc);
   switch (sfk)
 {
 case sfk_constructor:
-  if (type)
-   error_at (sm

[gcc r13-9333] c++: Friend classes don't shadow enclosing template class paramater [PR118255]

2025-01-19 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:b5d697817bbbc3f40ed74950d287a2c253318d36

commit r13-9333-gb5d697817bbbc3f40ed74950d287a2c253318d36
Author: Simon Martin 
Date:   Sun Jan 5 10:36:47 2025 +0100

c++: Friend classes don't shadow enclosing template class paramater 
[PR118255]

We currently reject the following code

=== code here ===
template  struct S { friend class non_template; };
class non_template {};
S<0> s;
=== code here ===

While EDG agrees with the current behaviour, clang and MSVC don't (see
https://godbolt.org/z/69TGaabhd), and I believe that this code is valid,
since the friend clause does not actually declare a type, so it cannot
shadow anything. The fact that we didn't error out if the non_template
class was declared before S backs this up as well.

This patch fixes this by skipping the call to check_template_shadow for
hidden bindings.

PR c++/118255

gcc/cp/ChangeLog:

* name-lookup.cc (pushdecl): Don't call check_template_shadow
for hidden bindings.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/pr99116-1.C: Adjust test expectation.
* g++.dg/template/friend84.C: New test.

(cherry picked from commit b5a069203fc074ab75d994c4a7e0f2db6a0a00fd)

Diff:
---
 gcc/cp/name-lookup.cc|  5 -
 gcc/testsuite/g++.dg/lookup/pr99116-1.C  |  2 +-
 gcc/testsuite/g++.dg/template/friend84.C | 26 ++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 1ea25f076b85..89f28caf183d 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3743,7 +3743,10 @@ pushdecl (tree decl, bool hiding)
   if (old && anticipated_builtin_p (old))
old = OVL_CHAIN (old);
 
-  check_template_shadow (decl);
+  if (hiding)
+   ; /* Hidden bindings don't shadow anything.  */
+  else
+   check_template_shadow (decl);
 
   if (DECL_DECLARES_FUNCTION_P (decl))
{
diff --git a/gcc/testsuite/g++.dg/lookup/pr99116-1.C 
b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
index 01b483ea9153..efee3e4aca36 100644
--- a/gcc/testsuite/g++.dg/lookup/pr99116-1.C
+++ b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
@@ -2,7 +2,7 @@
 
 template struct Z {
 
-  friend struct T; // { dg-error "shadows template parameter" }
+  friend struct T; // { dg-bogus "shadows template parameter" }
 };
 
 struct Y {
diff --git a/gcc/testsuite/g++.dg/template/friend84.C 
b/gcc/testsuite/g++.dg/template/friend84.C
new file mode 100644
index ..64ea41a552ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend84.C
@@ -0,0 +1,26 @@
+// PR c++/118255
+// { dg-do "compile" }
+
+// The PR's case, that used to error out.
+template 
+struct S {
+  friend class non_template; // { dg-bogus "shadows template parameter" }
+};
+
+class non_template {};
+S<0> s;
+
+// We already accepted cases where the friend is already declared.
+template 
+struct T {
+  friend class non_template;
+};
+T<0> t;
+
+// We should reject (re)declarations.
+template 
+struct U {
+  class non_template {};  // { dg-error "shadows template parameter" }
+  void non_template () {} // { dg-error "shadows template parameter" }
+};
+U<0> u;


[gcc r14-11226] c++: Friend classes don't shadow enclosing template class paramater [PR118255]

2025-01-19 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:b1f9fb0e133e9654caecb4a6b133ce559f21ca6a

commit r14-11226-gb1f9fb0e133e9654caecb4a6b133ce559f21ca6a
Author: Simon Martin 
Date:   Sun Jan 5 10:36:47 2025 +0100

c++: Friend classes don't shadow enclosing template class paramater 
[PR118255]

We currently reject the following code

=== code here ===
template  struct S { friend class non_template; };
class non_template {};
S<0> s;
=== code here ===

While EDG agrees with the current behaviour, clang and MSVC don't (see
https://godbolt.org/z/69TGaabhd), and I believe that this code is valid,
since the friend clause does not actually declare a type, so it cannot
shadow anything. The fact that we didn't error out if the non_template
class was declared before S backs this up as well.

This patch fixes this by skipping the call to check_template_shadow for
hidden bindings.

PR c++/118255

gcc/cp/ChangeLog:

* name-lookup.cc (pushdecl): Don't call check_template_shadow
for hidden bindings.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/pr99116-1.C: Adjust test expectation.
* g++.dg/template/friend84.C: New test.

(cherry picked from commit b5a069203fc074ab75d994c4a7e0f2db6a0a00fd)

Diff:
---
 gcc/cp/name-lookup.cc|  5 -
 gcc/testsuite/g++.dg/lookup/pr99116-1.C  |  2 +-
 gcc/testsuite/g++.dg/template/friend84.C | 26 ++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index b752598564a3..309f8fdadcb3 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4001,7 +4001,10 @@ pushdecl (tree decl, bool hiding)
   if (old && anticipated_builtin_p (old))
old = OVL_CHAIN (old);
 
-  check_template_shadow (decl);
+  if (hiding)
+   ; /* Hidden bindings don't shadow anything.  */
+  else
+   check_template_shadow (decl);
 
   if (DECL_DECLARES_FUNCTION_P (decl))
{
diff --git a/gcc/testsuite/g++.dg/lookup/pr99116-1.C 
b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
index 01b483ea9153..efee3e4aca36 100644
--- a/gcc/testsuite/g++.dg/lookup/pr99116-1.C
+++ b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
@@ -2,7 +2,7 @@
 
 template struct Z {
 
-  friend struct T; // { dg-error "shadows template parameter" }
+  friend struct T; // { dg-bogus "shadows template parameter" }
 };
 
 struct Y {
diff --git a/gcc/testsuite/g++.dg/template/friend84.C 
b/gcc/testsuite/g++.dg/template/friend84.C
new file mode 100644
index ..64ea41a552ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend84.C
@@ -0,0 +1,26 @@
+// PR c++/118255
+// { dg-do "compile" }
+
+// The PR's case, that used to error out.
+template 
+struct S {
+  friend class non_template; // { dg-bogus "shadows template parameter" }
+};
+
+class non_template {};
+S<0> s;
+
+// We already accepted cases where the friend is already declared.
+template 
+struct T {
+  friend class non_template;
+};
+T<0> t;
+
+// We should reject (re)declarations.
+template 
+struct U {
+  class non_template {};  // { dg-error "shadows template parameter" }
+  void non_template () {} // { dg-error "shadows template parameter" }
+};
+U<0> u;


[gcc r15-7091] testsuite: Fix test failing with -fimplicit-constexpr [PR118277]

2025-01-21 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:f3d884da1280e211f48be0619e5d2f1ee787

commit r15-7091-gf3d884da1280e211f48be0619e5d2f1ee787
Author: Simon Martin 
Date:   Tue Jan 21 10:11:12 2025 +0100

testsuite: Fix test failing with -fimplicit-constexpr [PR118277]

While testing an unrelated C++ patch with "make check-c++-all", I
noticed that r15-6760-g38a13ea4117b96 added a test case that fails with
-fimplicit-constexpr.

The problem is that this test unconditionally expects an error stating
that a non-constexpr function is called, but that function is
auto-magically constexpr'd under -fimplicit-constexpr.

As suggested by Jakub, this patch simply passes -fno-implicit-constexpr
in that test.

PR c++/118277

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/constexpr-asm-5.C: Pass -fno-implicit-constexpr.

Diff:
---
 gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C
index 1c20b9dfec1e..bcecea9d6b50 100644
--- a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C
@@ -2,7 +2,7 @@
 // { dg-do compile { target c++11 } }
 // { dg-options "" }
 // Override any default-'-fno-exceptions':
-// { dg-additional-options -fexceptions }
+// { dg-additional-options "-fexceptions -fno-implicit-constexpr" }
 
 struct A {};
 struct B { int size; };


[gcc r15-7122] c++: Clear TARGET_EXPR_ELIDING_P when forced to use a copy constructor due to __no_unique_address__

2025-01-22 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:e13e751d8144c9cfb7a9f1cd38119d1fa4ab38cf

commit r15-7122-ge13e751d8144c9cfb7a9f1cd38119d1fa4ab38cf
Author: Simon Martin 
Date:   Wed Jan 22 10:44:32 2025 +0100

c++: Clear TARGET_EXPR_ELIDING_P when forced to use a copy constructor due 
to __no_unique_address__ [PR118199]

We currently fail with a checking assert upon the following valid code
when using -fno-elide-constructors

=== cut here ===
struct d { ~d(); };
d &b();
struct f {
  [[__no_unique_address__]] d e;
};
struct h : f  {
  h() : f{b()} {}
} i;
=== cut here ===

The problem is that split_nonconstant_init_1 detects that it cannot
elide the copy constructor due to __no_unique_address__ but does not
clear TARGET_EXPR_ELIDING_P, and due to -fno-elide-constructors, we trip
on a checking assert in cp_gimplify_expr.

This patch fixes this by making sure that we clear TARGET_EXPR_ELIDING_P
if we determine that we have to keep the copy constructor due to
__no_unique_address__. An alternative would be to just check for
elide_constructors in that assert, but I think it'd lose most of its
value if we did so.

PR c++/118199

gcc/cp/ChangeLog:

* typeck2.cc (split_nonconstant_init_1): Clear
TARGET_EXPR_ELIDING_P if we need to use a copy constructor
because of __no_unique_address__.

gcc/testsuite/ChangeLog:

* g++.dg/init/no-elide3.C: New test.

Diff:
---
 gcc/cp/typeck2.cc |  5 +
 gcc/testsuite/g++.dg/init/no-elide3.C | 12 
 2 files changed, 17 insertions(+)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 15528baf0427..e88f6f0ad51d 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -655,6 +655,11 @@ split_nonconstant_init_1 (tree dest, tree init, bool last,
  && make_safe_copy_elision (sub, value))
goto build_init;
 
+ if (TREE_CODE (value) == TARGET_EXPR)
+   /* We have to add this constructor, so we will not
+  elide.  */
+   TARGET_EXPR_ELIDING_P (value) = false;
+
  tree name = (DECL_FIELD_IS_BASE (field_index)
   ? base_ctor_identifier
   : complete_ctor_identifier);
diff --git a/gcc/testsuite/g++.dg/init/no-elide3.C 
b/gcc/testsuite/g++.dg/init/no-elide3.C
new file mode 100644
index ..659eb19bc95a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/no-elide3.C
@@ -0,0 +1,12 @@
+// PR c++/118199
+// { dg-do "compile" { target c++11 } }
+// { dg-options "-fno-elide-constructors" } 
+
+struct d { ~d(); };
+d &b();
+struct f {
+  [[__no_unique_address__]] d e;
+};
+struct h : f  {
+  h() : f{b()} {}
+} i;


[gcc r12-10919] c++: Friend classes don't shadow enclosing template class paramater [PR118255]

2025-01-20 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:7bb462dd2a6a6551d142e7ad983fa2afd1df9253

commit r12-10919-g7bb462dd2a6a6551d142e7ad983fa2afd1df9253
Author: Simon Martin 
Date:   Sun Jan 5 10:36:47 2025 +0100

c++: Friend classes don't shadow enclosing template class paramater 
[PR118255]

We currently reject the following code

=== code here ===
template  struct S { friend class non_template; };
class non_template {};
S<0> s;
=== code here ===

While EDG agrees with the current behaviour, clang and MSVC don't (see
https://godbolt.org/z/69TGaabhd), and I believe that this code is valid,
since the friend clause does not actually declare a type, so it cannot
shadow anything. The fact that we didn't error out if the non_template
class was declared before S backs this up as well.

This patch fixes this by skipping the call to check_template_shadow for
hidden bindings.

PR c++/118255

gcc/cp/ChangeLog:

* name-lookup.cc (pushdecl): Don't call check_template_shadow
for hidden bindings.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/pr99116-1.C: Adjust test expectation.
* g++.dg/template/friend84.C: New test.

(cherry picked from commit b5a069203fc074ab75d994c4a7e0f2db6a0a00fd)

Diff:
---
 gcc/cp/name-lookup.cc|  5 -
 gcc/testsuite/g++.dg/lookup/pr99116-1.C  |  2 +-
 gcc/testsuite/g++.dg/template/friend84.C | 26 ++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 48c7badc865c..41bd4dd8dcac 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3741,7 +3741,10 @@ pushdecl (tree decl, bool hiding)
   if (old && anticipated_builtin_p (old))
old = OVL_CHAIN (old);
 
-  check_template_shadow (decl);
+  if (hiding)
+   ; /* Hidden bindings don't shadow anything.  */
+  else
+   check_template_shadow (decl);
 
   if (DECL_DECLARES_FUNCTION_P (decl))
{
diff --git a/gcc/testsuite/g++.dg/lookup/pr99116-1.C 
b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
index 01b483ea9153..efee3e4aca36 100644
--- a/gcc/testsuite/g++.dg/lookup/pr99116-1.C
+++ b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
@@ -2,7 +2,7 @@
 
 template struct Z {
 
-  friend struct T; // { dg-error "shadows template parameter" }
+  friend struct T; // { dg-bogus "shadows template parameter" }
 };
 
 struct Y {
diff --git a/gcc/testsuite/g++.dg/template/friend84.C 
b/gcc/testsuite/g++.dg/template/friend84.C
new file mode 100644
index ..64ea41a552ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend84.C
@@ -0,0 +1,26 @@
+// PR c++/118255
+// { dg-do "compile" }
+
+// The PR's case, that used to error out.
+template 
+struct S {
+  friend class non_template; // { dg-bogus "shadows template parameter" }
+};
+
+class non_template {};
+S<0> s;
+
+// We already accepted cases where the friend is already declared.
+template 
+struct T {
+  friend class non_template;
+};
+T<0> t;
+
+// We should reject (re)declarations.
+template 
+struct U {
+  class non_template {};  // { dg-error "shadows template parameter" }
+  void non_template () {} // { dg-error "shadows template parameter" }
+};
+U<0> u;


[gcc r15-7238] c++: Don't prune constant capture proxies only used in array dimensions [PR114292]

2025-01-27 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:ceabea405ffdc851736e240111be9b297ad86c53

commit r15-7238-gceabea405ffdc851736e240111be9b297ad86c53
Author: Simon Martin 
Date:   Wed Jan 22 16:19:47 2025 +0100

c++: Don't prune constant capture proxies only used in array dimensions 
[PR114292]

We currently ICE upon the following valid (under -Wno-vla) code

=== cut here ===
void f(int c) {
  constexpr int r = 4;
  [&](auto) { int t[r * c]; }(0);
}
=== cut here ===

When parsing the lambda body, and more specifically the multiplication,
we mark the lambda as LAMBDA_EXPR_CAPTURE_OPTIMIZED, which indicates to
prune_lambda_captures that it might be possible to optimize out some
captures.

The problem is that prune_lambda_captures then misses the use of the r
capture (because neither walk_tree_1 nor cp_walk_subtrees walks the
dimensions of array types - here "r * c"), hence believes the capture
can be pruned... and we trip on an assert when instantiating the lambda.

This patch changes cp_walk_subtrees so that (1) when walking a
DECL_EXPR, it also walks the DECL's type, and (2) when walking an
INTEGER_TYPE, it also walks its TYPE_{MIN,MAX}_VALUE. Note that #2 makes
a  redundant in for_each_template_parm_r, and removes
it.

PR c++/114292

gcc/cp/ChangeLog:

* pt.cc (for_each_template_parm_r) : Remove case
now handled by cp_walk_subtrees.
* tree.cc (cp_walk_subtrees): Walk the type of DECL_EXPR
declarations, as well as the TYPE_{MIN,MAX}_VALUE of
INTEGER_TYPEs.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/lambda-ice4.C: New test.

Diff:
---
 gcc/cp/pt.cc |  5 ---
 gcc/cp/tree.cc   |  7 
 gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C | 63 
 3 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6442ae947c32..d4a6e2e0675f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10822,11 +10822,6 @@ for_each_template_parm_r (tree *tp, int 
*walk_subtrees, void *d)
WALK_SUBTREE (TYPE_TI_ARGS (t));
   break;
 
-case INTEGER_TYPE:
-  WALK_SUBTREE (TYPE_MIN_VALUE (t));
-  WALK_SUBTREE (TYPE_MAX_VALUE (t));
-  break;
-
 case METHOD_TYPE:
   /* Since we're not going to walk subtrees, we have to do this
 explicitly here.  */
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 36581865a177..e35432f43af9 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5793,6 +5793,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
  && !TREE_STATIC (TREE_OPERAND (t, 0)
{
  tree decl = TREE_OPERAND (t, 0);
+ WALK_SUBTREE (TREE_TYPE (decl));
  WALK_SUBTREE (DECL_INITIAL (decl));
  WALK_SUBTREE (DECL_SIZE (decl));
  WALK_SUBTREE (DECL_SIZE_UNIT (decl));
@@ -5843,6 +5844,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
   WALK_SUBTREE (STATIC_ASSERT_MESSAGE (t));
   break;
 
+case INTEGER_TYPE:
+  /* Removed from walk_type_fields in r119481.  */
+  WALK_SUBTREE (TYPE_MIN_VALUE (t));
+  WALK_SUBTREE (TYPE_MAX_VALUE (t));
+  break;
+
 default:
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
new file mode 100644
index ..d8b7af9f9920
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
@@ -0,0 +1,63 @@
+// PR c++/114292
+// { dg-do "compile" { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define ASSERT_CAPTURE_NUMBER(Lambda, NumCaptures) \
+  { \
+auto oneCapture = [&](auto) { int t[c]; }; \
+const auto sizeOneCapture = sizeof (oneCapture); \
+const auto expected = NumCaptures ? NumCaptures * sizeOneCapture : 1; \
+static_assert (sizeof (Lambda) == expected, ""); \
+  }
+
+template
+struct Want_a_Typedef { typedef int Type[r*c]; };
+
+void foo (int c)
+{
+  constexpr int r = 4;
+
+  // This used to ICE.
+  auto ice_1 = [&](auto) { int t[c * r]; };
+  ice_1 (0);
+  ASSERT_CAPTURE_NUMBER (ice_1, 2);
+
+  // Another ICE identified following a great question in the patch submission
+  // mail thread.
+  auto ice_2 = [&](auto) { typedef int MyT[c*r]; };
+  ice_2 (0);
+  ASSERT_CAPTURE_NUMBER (ice_2, 2);
+
+  // All those worked already, but were not covered by any test - do it here.
+  auto ok_0 = [&](auto) { typedef int MyT[c*r]; MyT t; };
+  ok_0 (0);
+  ASSERT_CAPTURE_NUMBER (ok_0, 2);
+
+  auto ok_1 = [&](auto) { Want_a_Typedef::Type t; };
+  ok_1 (0);
+  ASSERT_CAPTURE_NUMBER (ok_1, 0);
+
+  auto ok_2 = [&](auto) { int t[c]; };
+  ok_2 (0);
+  ASSERT_CAPTURE_NUMBER (ok_2, 1);
+
+  auto ok_3 = [&](auto) { int n = r * c; int t[n]; };
+  ok_3 (0);
+  ASSERT_CAPTURE_NUMBER (ok_3, 2);
+
+  auto ok_4 = [&](auto) { int t[r]; }

[gcc r15-7096] c++: Don't ICE in build_class_member_access_expr during error recovery [PR118225]

2025-01-21 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:4e4c378ac1f923a310fa31be85ed8c0c50e9f5ef

commit r15-7096-g4e4c378ac1f923a310fa31be85ed8c0c50e9f5ef
Author: Simon Martin 
Date:   Tue Jan 21 13:31:41 2025 +0100

c++: Don't ICE in build_class_member_access_expr during error recovery 
[PR118225]

The invalid case in this PR trips on an assertion in
build_class_member_access_expr that build_base_path would never return
an error_mark_node, which is actually incorrect if the object involves a
tree with an error_mark_node DECL_INITIAL, like here.

This patch changes the assert to not fire if an error has been reported.

PR c++/118225

gcc/cp/ChangeLog:

* typeck.cc (build_class_member_access_expr): Let errors that
that have been reported go through.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/typeck.cc |  2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C | 17 +
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 3e0d71102abd..6b549809243a 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -2980,7 +2980,7 @@ build_class_member_access_expr (cp_expr object, tree 
member,
/*nonnull=*/1, complain);
  /* If we found the base successfully then we should be able
 to convert to it successfully.  */
- gcc_assert (object != error_mark_node);
+ gcc_assert (object != error_mark_node || seen_error ());
}
 
   /* If MEMBER is from an anonymous aggregate, we have converted
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C
new file mode 100644
index ..46273654f240
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C
@@ -0,0 +1,17 @@
+// PR c++/118225
+// { dg-do "compile" { target c++11} }
+
+struct NoMut1 { int a, b; };
+struct NoMut3 : virtual NoMut1 {
+  constexpr NoMut3(int a, int b) // { dg-error "virtual base" "" { target 
c++23 } }
+: NoMut1{a, b}
+  {} // { dg-error "virtual base" }
+};
+void mutable_subobjects() {
+  constexpr NoMut3 nm3 = {1, 2}; // { dg-error "call to non" }
+  struct A {
+void f() {
+  static_assert(nm3.a == 1, ""); // { dg-error "local variable" }
+}
+  };
+}


[gcc r15-7209] c++: Reinstate check for uninitialized bases with c++ <= 17 [PR118239]

2025-01-25 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:bee1910b891f897fcd1789d1dbd3937621354943

commit r15-7209-gbee1910b891f897fcd1789d1dbd3937621354943
Author: Simon Martin 
Date:   Sat Jan 25 18:09:23 2025 +0100

c++: Reinstate check for uninitialized bases with c++ <= 17 [PR118239]

We currently accept this code with c++ <= 17 even though it's invalid
since the base is not initialized (we properly reject it with c++ >= 20)

=== cut here ===
struct NoMut1 { int a, b; };
struct NoMut3 : NoMut1 {
  constexpr NoMut3(int a, int b) {}
};
void mutable_subobjects() {
  constexpr NoMut3 nm3(1, 2);
}
=== cut here ===

This is a fallout of r0-118700-gc2b3ec18a494e3, that ignores all fields
with DECL_ARTIFICIAL in cx_check_missing_mem_inits, including those that
represent base classes, and need to be checked.

This patch makes sure that we only skip fields that have DECL_ARTIFICIAL
if they don't have DECL_FIELD_IS_BASE.

PR c++/118239

gcc/cp/ChangeLog:

* constexpr.cc (cx_check_missing_mem_inits): Don't skip fields
with DECL_FIELD_IS_BASE.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/constexpr.cc  |  8 
 gcc/testsuite/g++.dg/cpp0x/constexpr-base8.C | 24 
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 41ff78bbf2b9..94a468056f90 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -839,9 +839,8 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool 
complain)
   if (i < nelts)
{
  index = CONSTRUCTOR_ELT (body, i)->index;
- /* Skip base and vtable inits.  */
- if (TREE_CODE (index) != FIELD_DECL
- || DECL_ARTIFICIAL (index))
+ /* Skip vptr adjustment represented with a COMPONENT_REF.  */
+ if (TREE_CODE (index) != FIELD_DECL)
continue;
}
 
@@ -852,7 +851,8 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool 
complain)
continue;
  if (DECL_UNNAMED_BIT_FIELD (field))
continue;
- if (DECL_ARTIFICIAL (field))
+ /* Artificial fields can be ignored unless they're bases.  */
+ if (DECL_ARTIFICIAL (field) && !DECL_FIELD_IS_BASE (field))
continue;
  if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-base8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-base8.C
new file mode 100644
index ..ecc28693315e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-base8.C
@@ -0,0 +1,24 @@
+// PR c++/118239
+// { dg-do "compile" { target c++11 } }
+
+struct NoMut1 {
+  int a, b;
+};
+
+// Reported case.
+struct NoMut2 : NoMut1 {
+  constexpr NoMut2(int a, int b) /*: NoMut1()*/
+  {} // { dg-error "must be initialized" "" { target c++17_down } }
+};
+
+// Variant with explicit initialization of some member.
+struct NoMut3 : NoMut1 {
+  constexpr NoMut3(int a, int b) : c(0) /*, NoMut1()*/
+  {} // { dg-error "must be initialized" "" { target c++17_down } }
+  int c;
+};
+
+void mutable_subobjects() {
+  constexpr NoMut2 nm2(1, 2); // { dg-error "constant expression" }
+  constexpr NoMut3 nm3(1, 2); // { dg-error "constant expression" }
+}


[gcc r15-6424] libcc1: Fix tags generation target

2024-12-23 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:6c59463a6fc6cd3ed4d0aad492af40c7ddd12f2a

commit r15-6424-g6c59463a6fc6cd3ed4d0aad492af40c7ddd12f2a
Author: Simon Martin 
Date:   Mon Dec 23 13:28:31 2024 +0100

libcc1: Fix tags generation target

'make tags' currently fails for libcc1 with this:
 *** No rule to make target `marshall-c.hh', needed by `tags-am'.  Stop.

The problem is that while marshall-c.hh has been removed via
r12-454-g25d1a6ecdc443f, it's still part of the libcc1_la_SOURCES
variable, hence the 'tags' target has a dependency on it.

This patch simply removes the marshall_c_source variable, that should be
empty.

libcc1/ChangeLog:

* Makefile.am: Remove reference to deleted marshall-c.h.
* Makefile.in: Regenerate.

Diff:
---
 libcc1/Makefile.am | 5 ++---
 libcc1/Makefile.in | 9 -
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am
index b592bc8645f1..062f4a74cc23 100644
--- a/libcc1/Makefile.am
+++ b/libcc1/Makefile.am
@@ -51,12 +51,11 @@ endif
 shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
 marshall.cc marshall.hh rpc.hh status.hh
 
-marshall_c_source = marshall-c.hh
 marshall_cxx_source = marshall-cp.hh
 
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = libcc1plugin.cc context.cc context.hh \
-   $(shared_source) $(marshall_c_source)
+   $(shared_source)
 libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
 libcc1plugin_la_LIBADD = $(libiberty)
 libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
@@ -78,7 +77,7 @@ LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags 
$(LDFLAGS))
 libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
 libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \
compiler.cc compiler.hh names.cc names.hh $(shared_source) \
-   $(marshall_c_source) $(marshall_cxx_source)
+   $(marshall_cxx_source)
 libcc1_la_LIBADD = $(libiberty)
 libcc1_la_DEPENDENCIES = $(libiberty_dep)
 libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in
index f8f590d71e9b..9d56a8323b05 100644
--- a/libcc1/Makefile.in
+++ b/libcc1/Makefile.in
@@ -145,11 +145,11 @@ LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
 am__objects_1 = callbacks.lo connection.lo marshall.lo
 am__objects_2 =
 am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo libcp1.lo compiler.lo \
-   names.lo $(am__objects_1) $(am__objects_2) $(am__objects_2)
+   names.lo $(am__objects_1) $(am__objects_2)
 libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
 am_libcc1plugin_la_OBJECTS = libcc1plugin.lo context.lo \
-   $(am__objects_1) $(am__objects_2)
+   $(am__objects_1)
 libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir)
 am_libcp1plugin_la_OBJECTS = libcp1plugin.lo context.lo \
@@ -403,11 +403,10 @@ cc1libdir = $(libdir)/$(libsuffix)
 shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
 marshall.cc marshall.hh rpc.hh status.hh
 
-marshall_c_source = marshall-c.hh
 marshall_cxx_source = marshall-cp.hh
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = libcc1plugin.cc context.cc context.hh \
-   $(shared_source) $(marshall_c_source)
+   $(shared_source)
 
 libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
 libcc1plugin_la_LIBADD = $(libiberty)
@@ -431,7 +430,7 @@ LTLDFLAGS = $(shell $(SHELL) 
$(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
 libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \
compiler.cc compiler.hh names.cc names.hh $(shared_source) \
-   $(marshall_c_source) $(marshall_cxx_source)
+   $(marshall_cxx_source)
 
 libcc1_la_LIBADD = $(libiberty)
 libcc1_la_DEPENDENCIES = $(libiberty_dep)


[gcc r15-6991] c++: Friend classes don't shadow enclosing template class paramater [PR118255]

2025-01-17 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:b5a069203fc074ab75d994c4a7e0f2db6a0a00fd

commit r15-6991-gb5a069203fc074ab75d994c4a7e0f2db6a0a00fd
Author: Simon Martin 
Date:   Sun Jan 5 10:36:47 2025 +0100

c++: Friend classes don't shadow enclosing template class paramater 
[PR118255]

We currently reject the following code

=== code here ===
template  struct S { friend class non_template; };
class non_template {};
S<0> s;
=== code here ===

While EDG agrees with the current behaviour, clang and MSVC don't (see
https://godbolt.org/z/69TGaabhd), and I believe that this code is valid,
since the friend clause does not actually declare a type, so it cannot
shadow anything. The fact that we didn't error out if the non_template
class was declared before S backs this up as well.

This patch fixes this by skipping the call to check_template_shadow for
hidden bindings.

PR c++/118255

gcc/cp/ChangeLog:

* name-lookup.cc (pushdecl): Don't call check_template_shadow
for hidden bindings.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/pr99116-1.C: Adjust test expectation.
* g++.dg/template/friend84.C: New test.

Diff:
---
 gcc/cp/name-lookup.cc|  5 -
 gcc/testsuite/g++.dg/lookup/pr99116-1.C  |  2 +-
 gcc/testsuite/g++.dg/template/friend84.C | 26 ++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 0e185d3ef426..d1abb205bc7f 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4040,7 +4040,10 @@ pushdecl (tree decl, bool hiding)
   if (old && anticipated_builtin_p (old))
old = OVL_CHAIN (old);
 
-  check_template_shadow (decl);
+  if (hiding)
+   ; /* Hidden bindings don't shadow anything.  */
+  else
+   check_template_shadow (decl);
 
   if (DECL_DECLARES_FUNCTION_P (decl))
{
diff --git a/gcc/testsuite/g++.dg/lookup/pr99116-1.C 
b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
index 01b483ea9153..efee3e4aca36 100644
--- a/gcc/testsuite/g++.dg/lookup/pr99116-1.C
+++ b/gcc/testsuite/g++.dg/lookup/pr99116-1.C
@@ -2,7 +2,7 @@
 
 template struct Z {
 
-  friend struct T; // { dg-error "shadows template parameter" }
+  friend struct T; // { dg-bogus "shadows template parameter" }
 };
 
 struct Y {
diff --git a/gcc/testsuite/g++.dg/template/friend84.C 
b/gcc/testsuite/g++.dg/template/friend84.C
new file mode 100644
index ..64ea41a552ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend84.C
@@ -0,0 +1,26 @@
+// PR c++/118255
+// { dg-do "compile" }
+
+// The PR's case, that used to error out.
+template 
+struct S {
+  friend class non_template; // { dg-bogus "shadows template parameter" }
+};
+
+class non_template {};
+S<0> s;
+
+// We already accepted cases where the friend is already declared.
+template 
+struct T {
+  friend class non_template;
+};
+T<0> t;
+
+// We should reject (re)declarations.
+template 
+struct U {
+  class non_template {};  // { dg-error "shadows template parameter" }
+  void non_template () {} // { dg-error "shadows template parameter" }
+};
+U<0> u;


[gcc r14-11220] c++: Make sure fold_sizeof_expr returns the correct type [PR117775]

2025-01-17 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:b4578c16a45756144f48f0f03ebe77b61762a022

commit r14-11220-gb4578c16a45756144f48f0f03ebe77b61762a022
Author: Simon Martin 
Date:   Thu Jan 16 16:27:06 2025 +0100

c++: Make sure fold_sizeof_expr returns the correct type [PR117775]

We currently ICE upon the following code, that is valid under
-Wno-pointer-arith:

=== cut here ===
int main() {
  decltype( [](auto) { return sizeof(void); } ) x;
  return x.operator()(0);
}
=== cut here ===

The problem is that "fold_sizeof_expr (sizeof(void))" returns
size_one_node, that has a different TREE_TYPE from that of the sizeof
expression, which later triggers an assert in cxx_eval_store_expression.

This patch makes sure that fold_sizeof_expr always returns a tree with
the size_type_node type.

PR c++/117775

gcc/cp/ChangeLog:

* decl.cc (fold_sizeof_expr): Make sure the folded result has
type size_type_node.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-117775.C: New test.

(cherry picked from commit 37f38b0f97374476a4818b68c8df991886428787)

Diff:
---
 gcc/cp/decl.cc|  1 +
 gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C | 13 +
 2 files changed, 14 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 02119105058e..529bfadf2e7d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -11502,6 +11502,7 @@ fold_sizeof_expr (tree t)
false, false);
   if (r == error_mark_node)
 r = size_one_node;
+  r = cp_fold_convert (size_type_node, r);
   return r;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C
new file mode 100644
index ..59fc0d332b92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C
@@ -0,0 +1,13 @@
+// PR c++/117775
+// Check that we don't ICE and have sizeof(void)==1 under -Wno-pointer-arith
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-Wno-pointer-arith" }
+
+int main() {
+  struct why :
+decltype( [](auto) {
+   return sizeof(void);
+ })
+  {} x;
+  return 1 - x.operator()(0);
+}


[gcc r13-9329] c++: Make sure fold_sizeof_expr returns the correct type [PR117775]

2025-01-17 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:fa248a92134c0681719702e60c369b916d4f8bf9

commit r13-9329-gfa248a92134c0681719702e60c369b916d4f8bf9
Author: Simon Martin 
Date:   Thu Jan 16 16:27:06 2025 +0100

c++: Make sure fold_sizeof_expr returns the correct type [PR117775]

We currently ICE upon the following code, that is valid under
-Wno-pointer-arith:

=== cut here ===
int main() {
  decltype( [](auto) { return sizeof(void); } ) x;
  return x.operator()(0);
}
=== cut here ===

The problem is that "fold_sizeof_expr (sizeof(void))" returns
size_one_node, that has a different TREE_TYPE from that of the sizeof
expression, which later triggers an assert in cxx_eval_store_expression.

This patch makes sure that fold_sizeof_expr always returns a tree with
the size_type_node type.

PR c++/117775

gcc/cp/ChangeLog:

* decl.cc (fold_sizeof_expr): Make sure the folded result has
type size_type_node.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-117775.C: New test.

(cherry picked from commit 37f38b0f97374476a4818b68c8df991886428787)

Diff:
---
 gcc/cp/decl.cc|  1 +
 gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C | 13 +
 2 files changed, 14 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index dbd1ee664c60..8f902fb1d114 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -11210,6 +11210,7 @@ fold_sizeof_expr (tree t)
false, false);
   if (r == error_mark_node)
 r = size_one_node;
+  r = cp_fold_convert (size_type_node, r);
   return r;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C
new file mode 100644
index ..59fc0d332b92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C
@@ -0,0 +1,13 @@
+// PR c++/117775
+// Check that we don't ICE and have sizeof(void)==1 under -Wno-pointer-arith
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-Wno-pointer-arith" }
+
+int main() {
+  struct why :
+decltype( [](auto) {
+   return sizeof(void);
+ })
+  {} x;
+  return 1 - x.operator()(0);
+}


[gcc r15-6972] c++: Make sure fold_sizeof_expr returns the correct type [PR117775]

2025-01-16 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:37f38b0f97374476a4818b68c8df991886428787

commit r15-6972-g37f38b0f97374476a4818b68c8df991886428787
Author: Simon Martin 
Date:   Thu Jan 16 16:27:06 2025 +0100

c++: Make sure fold_sizeof_expr returns the correct type [PR117775]

We currently ICE upon the following code, that is valid under
-Wno-pointer-arith:

=== cut here ===
int main() {
  decltype( [](auto) { return sizeof(void); } ) x;
  return x.operator()(0);
}
=== cut here ===

The problem is that "fold_sizeof_expr (sizeof(void))" returns
size_one_node, that has a different TREE_TYPE from that of the sizeof
expression, which later triggers an assert in cxx_eval_store_expression.

This patch makes sure that fold_sizeof_expr always returns a tree with
the size_type_node type.

PR c++/117775

gcc/cp/ChangeLog:

* decl.cc (fold_sizeof_expr): Make sure the folded result has
type size_type_node.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-117775.C: New test.

Diff:
---
 gcc/cp/decl.cc|  1 +
 gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C | 13 +
 2 files changed, 14 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index e5f8cd7ba702..ef887915ff1d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -11921,6 +11921,7 @@ fold_sizeof_expr (tree t)
false, false);
   if (r == error_mark_node)
 r = size_one_node;
+  r = cp_fold_convert (size_type_node, r);
   return r;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C
new file mode 100644
index ..59fc0d332b92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117775.C
@@ -0,0 +1,13 @@
+// PR c++/117775
+// Check that we don't ICE and have sizeof(void)==1 under -Wno-pointer-arith
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-Wno-pointer-arith" }
+
+int main() {
+  struct why :
+decltype( [](auto) {
+   return sizeof(void);
+ })
+  {} x;
+  return 1 - x.operator()(0);
+}


[gcc r15-7574] c++: Add testcase for now fixed issue [PR117324]

2025-02-16 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:6302f478433166f71464bc06caf5701c1800a7e7

commit r15-7574-g6302f478433166f71464bc06caf5701c1800a7e7
Author: Simon Martin 
Date:   Sun Feb 16 11:00:19 2025 +0100

c++: Add testcase for now fixed issue [PR117324]

The case in this PR does not ICE anymore after the fix for PR118319.

This patch simply adds the case to the testsuite.

PR c++/117324

gcc/testsuite/ChangeLog:

* g++.dg/parse/defarg19.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/parse/defarg19.C | 12 
 1 file changed, 12 insertions(+)

diff --git a/gcc/testsuite/g++.dg/parse/defarg19.C 
b/gcc/testsuite/g++.dg/parse/defarg19.C
new file mode 100644
index ..df0819ae6a5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg19.C
@@ -0,0 +1,12 @@
+// PR c++/117324
+// { dg-do "compile" { target c++11 } }
+
+template
+struct ct1 {
+  friend void f(ct1, // { dg-error "specifies default" }
+   int = [](int p = [] {}) { return p; }(); ) // { dg-error 
"expected|declares a non-template" }
+  {}
+};
+void test() {
+  f(ct1{}); // { dg-error "missing template arguments|not declared" "" { 
target c++14_down } }
+}


[gcc r14-11426] c++: Don't prune constant capture proxies only used in array dimensions [PR114292]

2025-03-20 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:f86d274ab76fdd89d7afd9b2eab28f3a61749cfb

commit r14-11426-gf86d274ab76fdd89d7afd9b2eab28f3a61749cfb
Author: Simon Martin 
Date:   Thu Mar 20 20:36:26 2025 +0100

c++: Don't prune constant capture proxies only used in array dimensions 
[PR114292]

We currently ICE upon the following valid (under -Wno-vla) code

=== cut here ===
void f(int c) {
  constexpr int r = 4;
  [&](auto) { int t[r * c]; }(0);
}
=== cut here ===

When parsing the lambda body, and more specifically the multiplication,
we mark the lambda as LAMBDA_EXPR_CAPTURE_OPTIMIZED, which indicates to
prune_lambda_captures that it might be possible to optimize out some
captures.

The problem is that prune_lambda_captures then misses the use of the r
capture (because neither walk_tree_1 nor cp_walk_subtrees walks the
dimensions of array types - here "r * c"), hence believes the capture
can be pruned... and we trip on an assert when instantiating the lambda.

This patch changes cp_walk_subtrees so that (1) when walking a
DECL_EXPR, it also walks the DECL's type, and (2) when walking an
INTEGER_TYPE and processing a template declaration, it also walks its
TYPE_{MIN,MAX}_VALUE.

PR c++/114292

gcc/cp/ChangeLog:

* tree.cc (cp_walk_subtrees): Walk the type of DECL_EXPR
declarations, as well as the TYPE_{MIN,MAX}_VALUE of
INTEGER_TYPEs for template declarations.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/lambda-ice4.C: New test.

Diff:
---
 gcc/cp/tree.cc   | 10 +
 gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C | 63 
 2 files changed, 73 insertions(+)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index abed2ce859c7..c6a4d89f4a34 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5701,6 +5701,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
  && !TREE_STATIC (TREE_OPERAND (t, 0)
{
  tree decl = TREE_OPERAND (t, 0);
+ WALK_SUBTREE (TREE_TYPE (decl));
  WALK_SUBTREE (DECL_INITIAL (decl));
  WALK_SUBTREE (DECL_SIZE (decl));
  WALK_SUBTREE (DECL_SIZE_UNIT (decl));
@@ -5751,6 +5752,15 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
   WALK_SUBTREE (STATIC_ASSERT_MESSAGE (t));
   break;
 
+case INTEGER_TYPE:
+  if (processing_template_decl)
+   {
+ /* Removed from walk_type_fields in r119481.  */
+ WALK_SUBTREE (TYPE_MIN_VALUE (t));
+ WALK_SUBTREE (TYPE_MAX_VALUE (t));
+   }
+  break;
+
 default:
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
new file mode 100644
index ..d8b7af9f9920
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
@@ -0,0 +1,63 @@
+// PR c++/114292
+// { dg-do "compile" { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define ASSERT_CAPTURE_NUMBER(Lambda, NumCaptures) \
+  { \
+auto oneCapture = [&](auto) { int t[c]; }; \
+const auto sizeOneCapture = sizeof (oneCapture); \
+const auto expected = NumCaptures ? NumCaptures * sizeOneCapture : 1; \
+static_assert (sizeof (Lambda) == expected, ""); \
+  }
+
+template
+struct Want_a_Typedef { typedef int Type[r*c]; };
+
+void foo (int c)
+{
+  constexpr int r = 4;
+
+  // This used to ICE.
+  auto ice_1 = [&](auto) { int t[c * r]; };
+  ice_1 (0);
+  ASSERT_CAPTURE_NUMBER (ice_1, 2);
+
+  // Another ICE identified following a great question in the patch submission
+  // mail thread.
+  auto ice_2 = [&](auto) { typedef int MyT[c*r]; };
+  ice_2 (0);
+  ASSERT_CAPTURE_NUMBER (ice_2, 2);
+
+  // All those worked already, but were not covered by any test - do it here.
+  auto ok_0 = [&](auto) { typedef int MyT[c*r]; MyT t; };
+  ok_0 (0);
+  ASSERT_CAPTURE_NUMBER (ok_0, 2);
+
+  auto ok_1 = [&](auto) { Want_a_Typedef::Type t; };
+  ok_1 (0);
+  ASSERT_CAPTURE_NUMBER (ok_1, 0);
+
+  auto ok_2 = [&](auto) { int t[c]; };
+  ok_2 (0);
+  ASSERT_CAPTURE_NUMBER (ok_2, 1);
+
+  auto ok_3 = [&](auto) { int n = r * c; int t[n]; };
+  ok_3 (0);
+  ASSERT_CAPTURE_NUMBER (ok_3, 2);
+
+  auto ok_4 = [&](auto) { int t[r]; };
+  ok_4 (0);
+  ASSERT_CAPTURE_NUMBER (ok_4, 0);
+
+  auto ok_5 = [&](auto) { int t[c * 4]; };
+  ok_5 (0);
+  ASSERT_CAPTURE_NUMBER (ok_5, 1);
+
+  auto ok_6 = [&](auto) { int t[1]; };
+  ok_6 (0);
+  ASSERT_CAPTURE_NUMBER (ok_6, 0);
+
+  auto ok_7 = [&](auto) { int t[c * r]; };
+  ok_7 (0);
+  ASSERT_CAPTURE_NUMBER (ok_7, 2);
+}


[gcc r13-9441] c++: Don't prune constant capture proxies only used in array dimensions [PR114292]

2025-03-21 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:65e998d172e006cdf0dd4d58f83784a5fed61fc5

commit r13-9441-g65e998d172e006cdf0dd4d58f83784a5fed61fc5
Author: Simon Martin 
Date:   Fri Mar 21 07:02:20 2025 +0100

c++: Don't prune constant capture proxies only used in array dimensions 
[PR114292]

We currently ICE upon the following valid (under -Wno-vla) code

=== cut here ===
void f(int c) {
  constexpr int r = 4;
  [&](auto) { int t[r * c]; }(0);
}
=== cut here ===

When parsing the lambda body, and more specifically the multiplication,
we mark the lambda as LAMBDA_EXPR_CAPTURE_OPTIMIZED, which indicates to
prune_lambda_captures that it might be possible to optimize out some
captures.

The problem is that prune_lambda_captures then misses the use of the r
capture (because neither walk_tree_1 nor cp_walk_subtrees walks the
dimensions of array types - here "r * c"), hence believes the capture
can be pruned... and we trip on an assert when instantiating the lambda.

This patch changes cp_walk_subtrees so that (1) when walking a
DECL_EXPR, it also walks the DECL's type, and (2) when walking an
INTEGER_TYPE and processing a template declaration, it also walks its
TYPE_{MIN,MAX}_VALUE.

PR c++/114292

gcc/cp/ChangeLog:

* tree.cc (cp_walk_subtrees): Walk the type of DECL_EXPR
declarations, as well as the TYPE_{MIN,MAX}_VALUE of
INTEGER_TYPEs for template declarations.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/lambda-ice4.C: New test.

(cherry picked from commit f86d274ab76fdd89d7afd9b2eab28f3a61749cfb)

Diff:
---
 gcc/cp/tree.cc   | 10 +
 gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C | 63 
 2 files changed, 73 insertions(+)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index c35f15baca2b..8ccb4ba70615 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5663,6 +5663,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
  && !TREE_STATIC (TREE_OPERAND (*tp, 0)
{
  tree decl = TREE_OPERAND (*tp, 0);
+ WALK_SUBTREE (TREE_TYPE (decl));
  WALK_SUBTREE (DECL_INITIAL (decl));
  WALK_SUBTREE (DECL_SIZE (decl));
  WALK_SUBTREE (DECL_SIZE_UNIT (decl));
@@ -5713,6 +5714,15 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
   WALK_SUBTREE (STATIC_ASSERT_MESSAGE (*tp));
   break;
 
+case INTEGER_TYPE:
+  if (processing_template_decl)
+   {
+ /* Removed from walk_type_fields in r119481.  */
+ WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
+ WALK_SUBTREE (TYPE_MAX_VALUE (*tp));
+   }
+  break;
+
 default:
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
new file mode 100644
index ..d8b7af9f9920
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
@@ -0,0 +1,63 @@
+// PR c++/114292
+// { dg-do "compile" { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define ASSERT_CAPTURE_NUMBER(Lambda, NumCaptures) \
+  { \
+auto oneCapture = [&](auto) { int t[c]; }; \
+const auto sizeOneCapture = sizeof (oneCapture); \
+const auto expected = NumCaptures ? NumCaptures * sizeOneCapture : 1; \
+static_assert (sizeof (Lambda) == expected, ""); \
+  }
+
+template
+struct Want_a_Typedef { typedef int Type[r*c]; };
+
+void foo (int c)
+{
+  constexpr int r = 4;
+
+  // This used to ICE.
+  auto ice_1 = [&](auto) { int t[c * r]; };
+  ice_1 (0);
+  ASSERT_CAPTURE_NUMBER (ice_1, 2);
+
+  // Another ICE identified following a great question in the patch submission
+  // mail thread.
+  auto ice_2 = [&](auto) { typedef int MyT[c*r]; };
+  ice_2 (0);
+  ASSERT_CAPTURE_NUMBER (ice_2, 2);
+
+  // All those worked already, but were not covered by any test - do it here.
+  auto ok_0 = [&](auto) { typedef int MyT[c*r]; MyT t; };
+  ok_0 (0);
+  ASSERT_CAPTURE_NUMBER (ok_0, 2);
+
+  auto ok_1 = [&](auto) { Want_a_Typedef::Type t; };
+  ok_1 (0);
+  ASSERT_CAPTURE_NUMBER (ok_1, 0);
+
+  auto ok_2 = [&](auto) { int t[c]; };
+  ok_2 (0);
+  ASSERT_CAPTURE_NUMBER (ok_2, 1);
+
+  auto ok_3 = [&](auto) { int n = r * c; int t[n]; };
+  ok_3 (0);
+  ASSERT_CAPTURE_NUMBER (ok_3, 2);
+
+  auto ok_4 = [&](auto) { int t[r]; };
+  ok_4 (0);
+  ASSERT_CAPTURE_NUMBER (ok_4, 0);
+
+  auto ok_5 = [&](auto) { int t[c * 4]; };
+  ok_5 (0);
+  ASSERT_CAPTURE_NUMBER (ok_5, 1);
+
+  auto ok_6 = [&](auto) { int t[1]; };
+  ok_6 (0);
+  ASSERT_CAPTURE_NUMBER (ok_6, 0);
+
+  auto ok_7 = [&](auto) { int t[c * r]; };
+  ok_7 (0);
+  ASSERT_CAPTURE_NUMBER (ok_7, 2);
+}


[gcc r13-9450] c++: Don't replace INDIRECT_REFs by a const capture proxy too eagerly [PR117504]

2025-03-25 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:f10853a0087bc115c8ee1ddb5fc641bffdb7f1a4

commit r13-9450-gf10853a0087bc115c8ee1ddb5fc641bffdb7f1a4
Author: Simon Martin 
Date:   Tue Mar 25 09:26:26 2025 +0100

c++: Don't replace INDIRECT_REFs by a const capture proxy too eagerly 
[PR117504]

We have been miscompiling the following valid code since GCC8, and
r8-3497-g281e6c1d8f1b4c

=== cut here ===
struct span {
  span (const int (&__first)[1]) : _M_ptr (__first) {}
  int operator[] (long __i) { return _M_ptr[__i]; }
  const int *_M_ptr;
};
void foo () {
  constexpr int a_vec[]{1};
  auto vec{[&a_vec]() -> span { return a_vec; }()};
}
=== cut here ===

The problem is that perform_implicit_conversion_flags (via
mark_rvalue_use) replaces "a_vec" in the return statement by a
CONSTRUCTOR representing a_vec's constant value, and then takes its
address when invoking span's constructor. So we end up with an instance
that points to garbage instead of a_vec's storage.

As per Jason's suggestion, this patch simply removes the calls to
mark_*_use from perform_implicit_conversion_flags, which fixes the PR.

PR c++/117504

gcc/cp/ChangeLog:

* call.cc (perform_implicit_conversion_flags): Don't call
mark_{l,r}value_use.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-117504.C: New test.
* g++.dg/cpp2a/constexpr-117504a.C: New test.

(cherry picked from commit fdf846fdddcc0467b9f025757f081c5d54319d08)

Diff:
---
 gcc/cp/call.cc |  5 ---
 gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C  | 60 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C | 12 ++
 3 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index d4aaeba94f6d..0cc235cb2b40 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13403,11 +13403,6 @@ perform_implicit_conversion_flags (tree type, tree 
expr,
   void *p;
   location_t loc = cp_expr_loc_or_input_loc (expr);
 
-  if (TYPE_REF_P (type))
-expr = mark_lvalue_use (expr);
-  else
-expr = mark_rvalue_use (expr);
-
   if (error_operand_p (expr))
 return error_mark_node;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C
new file mode 100644
index ..290d3dfd61e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C
@@ -0,0 +1,60 @@
+// PR c++/117504 - Initial report
+// { dg-do "run" { target c++20 } }
+
+struct span {
+  span (const int (&__first)[1]) : _M_ptr (__first) {}
+  int operator[] (long __i) { return _M_ptr[__i]; }
+  const int *_M_ptr;
+};
+
+constexpr int a_global_vec[]{1};
+span myFunctor() {
+  return a_global_vec;
+}
+
+int main() {
+  constexpr int a_vec[]{1};
+
+  //
+  // This PR's case, that used to be miscompiled.
+  //
+  auto lambda_1 = [&a_vec] () -> span { return a_vec; };
+  auto vec_1 { lambda_1 () };
+  if (vec_1[0] != 1)
+__builtin_abort ();
+
+  // Variant that used to be miscompiled as well.
+  auto lambda_2 = [&] () -> span { return a_vec; };
+  auto vec_2 { lambda_2 () };
+  if (vec_2[0] != 1)
+__builtin_abort ();
+
+  //
+  // Related cases that worked already.
+  //
+  auto lambda_3 = [&a_vec] () /* -> span */ { return a_vec; };
+  auto vec_3 { lambda_3 () };
+  if (vec_3[0] != 1)
+__builtin_abort ();
+
+  auto lambda_4 = [&] () /* -> span */ { return a_vec; };
+  auto vec_4 { lambda_4 () };
+  if (vec_4[0] != 1)
+__builtin_abort ();
+
+  const int (&vec_5)[1] = a_vec;
+  if (vec_5[0] != 1)
+__builtin_abort ();
+  
+  span vec_6 (a_vec);
+  if (vec_6[0] != 1)
+__builtin_abort ();
+
+  auto vec_7 = myFunctor ();
+  if (vec_7[0] != 1)
+__builtin_abort ();
+
+  const int (&vec_8)[1] { a_vec };
+  if (vec_8[0] != 1)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C
new file mode 100644
index ..f6d4dc8cbc53
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C
@@ -0,0 +1,12 @@
+// PR c++/117504 - ICE discovered by ppalka@ when reducing.
+// { dg-do "compile" { target c++20 } }
+
+struct span {
+  span (const int* __first) : _M_ptr (__first) {}
+  int operator[] (long __i) { return _M_ptr[__i]; }
+  const int *_M_ptr;
+};
+int main() {
+  constexpr int a_vec[]{1};
+  auto vec { [&a_vec]() -> span { return a_vec; } () };
+}


[gcc r15-8911] c++: Properly fold .* [PR114525]

2025-03-25 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:35ce9afc84a63fb647a90cbecb2adf3e748178be

commit r15-8911-g35ce9afc84a63fb647a90cbecb2adf3e748178be
Author: Simon Martin 
Date:   Tue Mar 25 20:11:19 2025 +0100

c++: Properly fold .* [PR114525]

We've been miscompiling the following since r0-51314-gd6b4ea8592e338 (I
did not go compile something that old, and identified this change via
git blame, so might be wrong)

=== cut here ===
struct Foo { int x; };
Foo& get (Foo &v) { return v; }
void bar () {
  Foo v; v.x = 1;
  (true ? get (v) : get (v)).*(&Foo::x) = 2;
  // v.x still equals 1 here...
}
=== cut here ===

The problem lies in build_m_component_ref, that computes the address of
the COND_EXPR using build_address to build the representation of
  (true ? get (v) : get (v)).*(&Foo::x);
and gets something like
  &(true ? get (v) : get (v))  // #1
instead of
  (true ? &get (v) : &get (v)) // #2
and the write does not go where want it to, hence the miscompile.

This patch replaces the call to build_address by a call to
cp_build_addr_expr, which gives #2, that is properly handled.

PR c++/114525

gcc/cp/ChangeLog:

* typeck2.cc (build_m_component_ref): Call cp_build_addr_expr
instead of build_address.

gcc/testsuite/ChangeLog:

* g++.dg/expr/cond18.C: New test.

Diff:
---
 gcc/cp/typeck2.cc  |  2 +-
 gcc/testsuite/g++.dg/expr/cond18.C | 36 
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 1adc05aa86dc..45edd1801739 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2387,7 +2387,7 @@ build_m_component_ref (tree datum, tree component, 
tsubst_flags_t complain)
  (cp_type_quals (type)
   | cp_type_quals (TREE_TYPE (datum;
 
-  datum = build_address (datum);
+  datum = cp_build_addr_expr (datum, complain);
 
   /* Convert object to the correct base.  */
   if (binfo)
diff --git a/gcc/testsuite/g++.dg/expr/cond18.C 
b/gcc/testsuite/g++.dg/expr/cond18.C
new file mode 100644
index ..326985eed506
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/cond18.C
@@ -0,0 +1,36 @@
+/* PR c++/114525 */
+/* { dg-do run } */
+
+struct Foo {
+  int x;
+};
+
+Foo& get (Foo& v) {
+  return v;
+}
+
+int main () {
+  bool cond = true;
+
+  /* Testcase from PR; v.x would wrongly remain equal to 1.  */
+  Foo v_ko;
+  v_ko.x = 1;
+  (cond ? get (v_ko) : get (v_ko)).*(&Foo::x) = 2;
+  if (v_ko.x != 2)
+__builtin_abort ();
+
+  /* Those would already work, i.e. x be changed to 2.  */
+  Foo v_ok_1;
+  v_ok_1.x = 1;
+  (cond ? get (v_ok_1) : get (v_ok_1)).x = 2;
+  if (v_ok_1.x != 2)
+__builtin_abort ();
+
+  Foo v_ok_2;
+  v_ok_2.x = 1;
+  get (v_ok_2).*(&Foo::x) = 2;
+  if (v_ok_2.x != 2)
+__builtin_abort ();
+
+  return 0;
+}


[gcc r14-11602] c++: Properly fold .* [PR114525]

2025-04-14 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:7e79c32ac1cc84f933000d5cc45249b2eb338aad

commit r14-11602-g7e79c32ac1cc84f933000d5cc45249b2eb338aad
Author: Simon Martin 
Date:   Mon Apr 14 08:36:06 2025 +0200

c++: Properly fold .* [PR114525]

We've been miscompiling the following since r0-51314-gd6b4ea8592e338 (I
did not go compile something that old, and identified this change via
git blame, so might be wrong)

=== cut here ===
struct Foo { int x; };
Foo& get (Foo &v) { return v; }
void bar () {
  Foo v; v.x = 1;
  (true ? get (v) : get (v)).*(&Foo::x) = 2;
  // v.x still equals 1 here...
}
=== cut here ===

The problem lies in build_m_component_ref, that computes the address of
the COND_EXPR using build_address to build the representation of
  (true ? get (v) : get (v)).*(&Foo::x);
and gets something like
  &(true ? get (v) : get (v))  // #1
instead of
  (true ? &get (v) : &get (v)) // #2
and the write does not go where want it to, hence the miscompile.

This patch replaces the call to build_address by a call to
cp_build_addr_expr, which gives #2, that is properly handled.

PR c++/114525

gcc/cp/ChangeLog:

* typeck2.cc (build_m_component_ref): Call cp_build_addr_expr
instead of build_address.

gcc/testsuite/ChangeLog:

* g++.dg/expr/cond18.C: New test.

(cherry picked from commit 35ce9afc84a63fb647a90cbecb2adf3e748178be)

Diff:
---
 gcc/cp/typeck2.cc  |  2 +-
 gcc/testsuite/g++.dg/expr/cond18.C | 36 
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index e32a4c638c59..3adb8dec1616 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2347,7 +2347,7 @@ build_m_component_ref (tree datum, tree component, 
tsubst_flags_t complain)
  (cp_type_quals (type)
   | cp_type_quals (TREE_TYPE (datum;
 
-  datum = build_address (datum);
+  datum = cp_build_addr_expr (datum, complain);
 
   /* Convert object to the correct base.  */
   if (binfo)
diff --git a/gcc/testsuite/g++.dg/expr/cond18.C 
b/gcc/testsuite/g++.dg/expr/cond18.C
new file mode 100644
index ..326985eed506
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/cond18.C
@@ -0,0 +1,36 @@
+/* PR c++/114525 */
+/* { dg-do run } */
+
+struct Foo {
+  int x;
+};
+
+Foo& get (Foo& v) {
+  return v;
+}
+
+int main () {
+  bool cond = true;
+
+  /* Testcase from PR; v.x would wrongly remain equal to 1.  */
+  Foo v_ko;
+  v_ko.x = 1;
+  (cond ? get (v_ko) : get (v_ko)).*(&Foo::x) = 2;
+  if (v_ko.x != 2)
+__builtin_abort ();
+
+  /* Those would already work, i.e. x be changed to 2.  */
+  Foo v_ok_1;
+  v_ok_1.x = 1;
+  (cond ? get (v_ok_1) : get (v_ok_1)).x = 2;
+  if (v_ok_1.x != 2)
+__builtin_abort ();
+
+  Foo v_ok_2;
+  v_ok_2.x = 1;
+  get (v_ok_2).*(&Foo::x) = 2;
+  if (v_ok_2.x != 2)
+__builtin_abort ();
+
+  return 0;
+}


[gcc r16-386] c++: Remove obsolete prototype

2025-05-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:20c2fc676050ebfcd62af50dad08cd2d2736d1e8

commit r16-386-g20c2fc676050ebfcd62af50dad08cd2d2736d1e8
Author: Simon Martin 
Date:   Mon May 5 10:37:52 2025 +0200

c++: Remove obsolete prototype

I noticed while investigating PR c++/119437 that r8-2724-g88b811bd290630
removed parsing_default_capturing_generic_lambda_in_template but not its
prototype in cp-tree.h.

This patch fixes this.

gcc/cp/ChangeLog:

* cp-tree.h (parsing_default_capturing_generic_lambda_in_template):
Remove obsolete prototype.

Diff:
---
 gcc/cp/cp-tree.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index af51d67ef9fe..a42c07a330bc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7632,7 +7632,6 @@ extern void cp_finish_omp_range_for (tree, tree);
 extern bool cp_maybe_parse_omp_decl (tree, tree);
 extern bool parsing_nsdmi (void);
 extern bool parsing_function_declarator ();
-extern bool parsing_default_capturing_generic_lambda_in_template (void);
 extern void inject_this_parameter (tree, cp_cv_quals);
 extern location_t defparse_location (tree);
 extern void maybe_show_extern_c_location (void);


[gcc r16-383] c++: Inhibit subsequent warnings/notes in diagnostic_groups with an inhibited warning [PR118163, PR11

2025-05-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:0f1d55a75b09c13e3db09654c2b5aaad5741262f

commit r16-383-g0f1d55a75b09c13e3db09654c2b5aaad5741262f
Author: Simon Martin 
Date:   Mon May 5 10:12:08 2025 +0200

c++: Inhibit subsequent warnings/notes in diagnostic_groups with an 
inhibited warning [PR118163,PR118392]

Those 2 PRs show that even when using a *single* diagnostic_group, it's
possible to end up with a warning being inhibited and its associated
note still emitted, which leads to puzzling user experience. Example
from PR118392:

===
$ gcc/cc1plus inhibit-warn-3.C -w
inhibit-warn-3.C:10:17: note: only here as a ‘friend’
   10 | friend void bar();
  | ^~~
===

Following a suggestion from ppalka@, this patch keeps track of the
"diagnostic depth" at which a warning in inhibited, and makes sure that
all subsequent notes at that depth or deeper are inhibited as well,
until a subsequent warning or error is accepted at that depth, or the
diagnostic_group or nesting level is popped.

PR c++/118163
PR c++/118392

gcc/ChangeLog:

* diagnostic.cc (diagnostic_context::initialize): Initialize
m_diagnostic_groups.m_inhibiting_notes_from.
(diagnostic_context::inhibit_notes_in_group): New.
(diagnostic_context::notes_inhibited_in_group): New
(diagnostic_context::report_diagnostic): Call
inhibit_notes_in_group and notes_inhibited_in_group.
(diagnostic_context::end_group): Call inhibit_notes_in_group.
(diagnostic_context::pop_nesting_level): Ditto.
* diagnostic.h (diagnostic_context::m_diagnostic_groups): Add
member to track the depth at which a warning has been inhibited.
(diagnostic_context::notes_inhibited_in_group): Declare.
(diagnostic_context::inhibit_notes_in_group): Declare.
* doc/ux.texi: Document diagnostic_group behavior with regards
to inhibited warnings.

gcc/testsuite/ChangeLog:

* g++.dg/diagnostic/incomplete-type-2.C: New test.
* g++.dg/diagnostic/incomplete-type-2a.C: New test.
* g++.dg/diagnostic/inhibit-warn-3.C: New test.

Diff:
---
 gcc/diagnostic.cc  | 67 +-
 gcc/diagnostic.h   |  6 ++
 gcc/doc/ux.texi|  5 +-
 .../g++.dg/diagnostic/incomplete-type-2.C  |  7 +++
 .../g++.dg/diagnostic/incomplete-type-2a.C | 13 +
 gcc/testsuite/g++.dg/diagnostic/inhibit-warn-3.C   | 15 +
 6 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 429c4b1b116a..c3ea1b34d2f2 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -282,6 +282,7 @@ diagnostic_context::initialize (int n_opts)
   m_diagnostic_groups.m_group_nesting_depth = 0;
   m_diagnostic_groups.m_diagnostic_nesting_level = 0;
   m_diagnostic_groups.m_emission_count = 0;
+  m_diagnostic_groups.m_inhibiting_notes_from = 0;
   m_output_sinks.safe_push
 (new diagnostic_text_output_format (*this, nullptr, true));
   m_set_locations_cb = nullptr;
@@ -917,6 +918,7 @@ diagnostic_context::check_max_errors (bool flush)
 
 /* Take any action which is expected to happen after the diagnostic
is written out.  This function does not always return.  */
+
 void
 diagnostic_context::action_after_output (diagnostic_t diag_kind)
 {
@@ -991,6 +993,50 @@ diagnostic_context::action_after_output (diagnostic_t 
diag_kind)
 }
 }
 
+/* State whether we should inhibit notes in the current diagnostic_group and
+   its future children if any.  */
+
+void
+diagnostic_context::inhibit_notes_in_group (bool inhibit)
+{
+  int curr_depth = (m_diagnostic_groups.m_group_nesting_depth
+   + m_diagnostic_groups.m_diagnostic_nesting_level);
+
+  if (inhibit)
+{
+  /* If we're already inhibiting, there's nothing to do.  */
+  if (m_diagnostic_groups.m_inhibiting_notes_from)
+   return;
+
+  /* Since we're called via warning/error/... that all have their own
+diagnostic_group, we must consider that we started inhibiting in their
+parent.  */
+  gcc_assert (m_diagnostic_groups.m_group_nesting_depth > 0);
+  m_diagnostic_groups.m_inhibiting_notes_from = curr_depth - 1;
+}
+  else if (m_diagnostic_groups.m_inhibiting_notes_from)
+{
+  /* Only cancel inhibition at the depth that set it up.  */
+  if (curr_depth >= m_diagnostic_groups.m_inhibiting_notes_from)
+   return;
+
+  m_diagnostic_groups.m_inhibiting_notes_from = 0;
+}
+}
+
+/* Return whether notes must be inhibited in the current diagnostic_group.  */
+
+bool
+diagnostic_context::notes_inhibited_in_group () const
+{
+  if (m_diagnostic_groups.m_inhibiting_notes_from
+  && (m_diagnostic_groups.m_group_nesting_depth
+ 

[gcc r13-9523] c++: Properly fold .* [PR114525]

2025-04-15 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:ca2b5edb99023d88c83ac6384e908fce6b546578

commit r13-9523-gca2b5edb99023d88c83ac6384e908fce6b546578
Author: Simon Martin 
Date:   Mon Apr 14 09:24:12 2025 +0200

c++: Properly fold .* [PR114525]

We've been miscompiling the following since r0-51314-gd6b4ea8592e338 (I
did not go compile something that old, and identified this change via
git blame, so might be wrong)

=== cut here ===
struct Foo { int x; };
Foo& get (Foo &v) { return v; }
void bar () {
  Foo v; v.x = 1;
  (true ? get (v) : get (v)).*(&Foo::x) = 2;
  // v.x still equals 1 here...
}
=== cut here ===

The problem lies in build_m_component_ref, that computes the address of
the COND_EXPR using build_address to build the representation of
  (true ? get (v) : get (v)).*(&Foo::x);
and gets something like
  &(true ? get (v) : get (v))  // #1
instead of
  (true ? &get (v) : &get (v)) // #2
and the write does not go where want it to, hence the miscompile.

This patch replaces the call to build_address by a call to
cp_build_addr_expr, which gives #2, that is properly handled.

PR c++/114525

gcc/cp/ChangeLog:

* typeck2.cc (build_m_component_ref): Call cp_build_addr_expr
instead of build_address.

gcc/testsuite/ChangeLog:

* g++.dg/expr/cond18.C: New test.

(cherry picked from commit 35ce9afc84a63fb647a90cbecb2adf3e748178be)

Diff:
---
 gcc/cp/typeck2.cc  |  2 +-
 gcc/testsuite/g++.dg/expr/cond18.C | 36 
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index e499bf0f20ce..775d18f61fd7 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2339,7 +2339,7 @@ build_m_component_ref (tree datum, tree component, 
tsubst_flags_t complain)
  (cp_type_quals (type)
   | cp_type_quals (TREE_TYPE (datum;
 
-  datum = build_address (datum);
+  datum = cp_build_addr_expr (datum, complain);
 
   /* Convert object to the correct base.  */
   if (binfo)
diff --git a/gcc/testsuite/g++.dg/expr/cond18.C 
b/gcc/testsuite/g++.dg/expr/cond18.C
new file mode 100644
index ..326985eed506
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/cond18.C
@@ -0,0 +1,36 @@
+/* PR c++/114525 */
+/* { dg-do run } */
+
+struct Foo {
+  int x;
+};
+
+Foo& get (Foo& v) {
+  return v;
+}
+
+int main () {
+  bool cond = true;
+
+  /* Testcase from PR; v.x would wrongly remain equal to 1.  */
+  Foo v_ko;
+  v_ko.x = 1;
+  (cond ? get (v_ko) : get (v_ko)).*(&Foo::x) = 2;
+  if (v_ko.x != 2)
+__builtin_abort ();
+
+  /* Those would already work, i.e. x be changed to 2.  */
+  Foo v_ok_1;
+  v_ok_1.x = 1;
+  (cond ? get (v_ok_1) : get (v_ok_1)).x = 2;
+  if (v_ok_1.x != 2)
+__builtin_abort ();
+
+  Foo v_ok_2;
+  v_ok_2.x = 1;
+  get (v_ok_2).*(&Foo::x) = 2;
+  if (v_ok_2.x != 2)
+__builtin_abort ();
+
+  return 0;
+}


[gcc r15-7887] vect: Fix build on MacOS

2025-03-07 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:22c0dabb7c6d6205042a6c0f8f9032d7875ffe88

commit r15-7887-g22c0dabb7c6d6205042a6c0f8f9032d7875ffe88
Author: Simon Martin 
Date:   Fri Mar 7 15:30:16 2025 +0100

vect: Fix build on MacOS

The build is broken on MacOS since r15-7881-ge8651b80aeb86d because
tree-vect-data-refs.cc uses std::min but does not include .

This patch fixes it by defining INCLUDE_ALGORITHM in that file.

gcc/ChangeLog:

* tree-vect-data-refs.cc: Define INCLUDE_ALGORITHM.

Diff:
---
 gcc/tree-vect-data-refs.cc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index 7c63916cf4f2..c9395e33fcdf 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public 
License
 along with GCC; see the file COPYING3.  If not see
 .  */
 
+#define INCLUDE_ALGORITHM
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"


[gcc r15-7849] c++: Don't replace INDIRECT_REFs by a const capture proxy too eagerly [PR117504]

2025-03-06 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:fdf846fdddcc0467b9f025757f081c5d54319d08

commit r15-7849-gfdf846fdddcc0467b9f025757f081c5d54319d08
Author: Simon Martin 
Date:   Thu Mar 6 10:10:45 2025 +0100

c++: Don't replace INDIRECT_REFs by a const capture proxy too eagerly 
[PR117504]

We have been miscompiling the following valid code since GCC8, and
r8-3497-g281e6c1d8f1b4c

=== cut here ===
struct span {
  span (const int (&__first)[1]) : _M_ptr (__first) {}
  int operator[] (long __i) { return _M_ptr[__i]; }
  const int *_M_ptr;
};
void foo () {
  constexpr int a_vec[]{1};
  auto vec{[&a_vec]() -> span { return a_vec; }()};
}
=== cut here ===

The problem is that perform_implicit_conversion_flags (via
mark_rvalue_use) replaces "a_vec" in the return statement by a
CONSTRUCTOR representing a_vec's constant value, and then takes its
address when invoking span's constructor. So we end up with an instance
that points to garbage instead of a_vec's storage.

As per Jason's suggestion, this patch simply removes the calls to
mark_*_use from perform_implicit_conversion_flags, which fixes the PR.

PR c++/117504

gcc/cp/ChangeLog:

* call.cc (perform_implicit_conversion_flags): Don't call
mark_{l,r}value_use.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-117504.C: New test.
* g++.dg/cpp2a/constexpr-117504a.C: New test.

Diff:
---
 gcc/cp/call.cc |  5 ---
 gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C  | 60 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C | 12 ++
 3 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index f7b4cccb1c7a..c1c8987ec8b1 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13971,11 +13971,6 @@ perform_implicit_conversion_flags (tree type, tree 
expr,
   conversion *conv;
   location_t loc = cp_expr_loc_or_input_loc (expr);
 
-  if (TYPE_REF_P (type))
-expr = mark_lvalue_use (expr);
-  else
-expr = mark_rvalue_use (expr);
-
   if (error_operand_p (expr))
 return error_mark_node;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C
new file mode 100644
index ..290d3dfd61e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C
@@ -0,0 +1,60 @@
+// PR c++/117504 - Initial report
+// { dg-do "run" { target c++20 } }
+
+struct span {
+  span (const int (&__first)[1]) : _M_ptr (__first) {}
+  int operator[] (long __i) { return _M_ptr[__i]; }
+  const int *_M_ptr;
+};
+
+constexpr int a_global_vec[]{1};
+span myFunctor() {
+  return a_global_vec;
+}
+
+int main() {
+  constexpr int a_vec[]{1};
+
+  //
+  // This PR's case, that used to be miscompiled.
+  //
+  auto lambda_1 = [&a_vec] () -> span { return a_vec; };
+  auto vec_1 { lambda_1 () };
+  if (vec_1[0] != 1)
+__builtin_abort ();
+
+  // Variant that used to be miscompiled as well.
+  auto lambda_2 = [&] () -> span { return a_vec; };
+  auto vec_2 { lambda_2 () };
+  if (vec_2[0] != 1)
+__builtin_abort ();
+
+  //
+  // Related cases that worked already.
+  //
+  auto lambda_3 = [&a_vec] () /* -> span */ { return a_vec; };
+  auto vec_3 { lambda_3 () };
+  if (vec_3[0] != 1)
+__builtin_abort ();
+
+  auto lambda_4 = [&] () /* -> span */ { return a_vec; };
+  auto vec_4 { lambda_4 () };
+  if (vec_4[0] != 1)
+__builtin_abort ();
+
+  const int (&vec_5)[1] = a_vec;
+  if (vec_5[0] != 1)
+__builtin_abort ();
+  
+  span vec_6 (a_vec);
+  if (vec_6[0] != 1)
+__builtin_abort ();
+
+  auto vec_7 = myFunctor ();
+  if (vec_7[0] != 1)
+__builtin_abort ();
+
+  const int (&vec_8)[1] { a_vec };
+  if (vec_8[0] != 1)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C
new file mode 100644
index ..f6d4dc8cbc53
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C
@@ -0,0 +1,12 @@
+// PR c++/117504 - ICE discovered by ppalka@ when reducing.
+// { dg-do "compile" { target c++20 } }
+
+struct span {
+  span (const int* __first) : _M_ptr (__first) {}
+  int operator[] (long __i) { return _M_ptr[__i]; }
+  const int *_M_ptr;
+};
+int main() {
+  constexpr int a_vec[]{1};
+  auto vec { [&a_vec]() -> span { return a_vec; } () };
+}


[gcc r15-7872] Fix comment typos

2025-03-06 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:be0942afb3a7080b7b0420a5369bdcf3dcc74b52

commit r15-7872-gbe0942afb3a7080b7b0420a5369bdcf3dcc74b52
Author: Simon Martin 
Date:   Thu Mar 6 20:36:26 2025 +0100

Fix comment typos

While investigating PR c++/99538 I noticed two comment typos: "delared"
and "paramter". The first has a single occurrence, but the second a few
more. This patch fixes all of them.

gcc/ChangeLog:

* config/i386/x86-tune-sched.cc (ix86_fuse_mov_alu_p): Fix
comment typo, paramter -> parameter.
* config/lm32/lm32.cc (lm32_std_gimplify_va_arg_expr): Likewise.

gcc/cp/ChangeLog:

* cp-tree.h (processing_contract_condition): Fix comment typo,
paramter -> parameter.
* parser.cc (cp_parser_requires_expression): Fix comment typo,
delared -> declared.

gcc/rust/ChangeLog:

* rust-diagnostics.h (RUST_ATTRIBUTE_GCC_DIAG): Fix comment
typo, paramter -> parameter.

gcc/testsuite/ChangeLog:

* gcc.target/powerpc/ppc64-abi-1.c: Fix comment typos, paramter
-> parameter.
* gcc.target/powerpc/ppc64-abi-2.c: Likewise.

Diff:
---
 gcc/config/i386/x86-tune-sched.cc  |  3 +--
 gcc/config/lm32/lm32.cc|  2 +-
 gcc/cp/cp-tree.h   |  2 +-
 gcc/cp/parser.cc   |  2 +-
 gcc/rust/rust-diagnostics.h|  2 +-
 gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c | 12 ++--
 gcc/testsuite/gcc.target/powerpc/ppc64-abi-2.c | 12 ++--
 7 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/gcc/config/i386/x86-tune-sched.cc 
b/gcc/config/i386/x86-tune-sched.cc
index a51764e078c8..685a83c4311b 100644
--- a/gcc/config/i386/x86-tune-sched.cc
+++ b/gcc/config/i386/x86-tune-sched.cc
@@ -633,7 +633,7 @@ ix86_fuse_mov_alu_p (rtx_insn *mov, rtx_insn *alu)
   && !REG_P (op1)
   && !x86_64_immediate_operand (op1, VOIDmode))
 return false;
-  /* Only one of two paramters must be move destination.  */
+  /* Only one of two parameters must be move destination.  */
   if (op1 && REG_P (op1) && REGNO (op1) == REGNO (reg))
 return false;
   return true;
@@ -786,4 +786,3 @@ ix86_macro_fusion_pair_p (rtx_insn *condgen, rtx_insn 
*condjmp)
 
   return true;
 }
-
diff --git a/gcc/config/lm32/lm32.cc b/gcc/config/lm32/lm32.cc
index 15728969fadd..9ec756cd478d 100644
--- a/gcc/config/lm32/lm32.cc
+++ b/gcc/config/lm32/lm32.cc
@@ -831,7 +831,7 @@ lm32_builtin_va_start (tree valist, rtx nextarg)
 
 /*
  * This was copied from "standard" implementation of va_arg, and then
- * handling for overflow of the register paramters added
+ * handling for overflow of the register parameters added.
  */
 
 static tree
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 583d04963642..a839ad6d28ac 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2025,7 +2025,7 @@ extern GTY(()) struct saved_scope *scope_chain;
 #define processing_omp_trait_property_expr 
scope_chain->x_processing_omp_trait_property_expr
 
 /* Nonzero if we are parsing the conditional expression of a contract
-   condition. These expressions appear outside the paramter list (like a
+   condition. These expressions appear outside the parameter list (like a
trailing return type), but are potentially evaluated.  */
 
 #define processing_contract_condition 
scope_chain->x_processing_contract_condition
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 489c00e05227..c2b81fc281a8 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -32299,7 +32299,7 @@ cp_parser_requires_expression (cp_parser *parser)
 
   tree parms, reqs;
   {
-/* Local parameters are delared as variables within the scope
+/* Local parameters are declared as variables within the scope
of the expression.  They are not visible past the end of
the expression.  Expressions within the requires-expression
are unevaluated.  */
diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h
index 42f3ba7fc6d8..a13dc6a2eaf8 100644
--- a/gcc/rust/rust-diagnostics.h
+++ b/gcc/rust/rust-diagnostics.h
@@ -25,7 +25,7 @@
 #include "util/optional.h"
 
 // This macro is used to specify the position of format string & it's
-// arguments within the function's paramter list.
+// arguments within the function's parameter list.
 // 'm' specifies the position of the format string parameter.
 // 'n' specifies the position of the first argument for the format string.
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c 
b/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c
index 731c0d880aa8..4a3329042bc4 100644
--- a/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c
+++ b/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c
@@ -102,7 +102,7 @@ typedef struct sf
 } stack_frame_t;
 
 
-/* Paramter passing.
+/* Parameter

[gcc r15-7991] cobol: Remove unnecesssary CPPFLAGS update and restore MacOS build

2025-03-12 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:503f10e34dcdeb8bd1cf78c2f14c7ac41cae31a5

commit r15-7991-g503f10e34dcdeb8bd1cf78c2f14c7ac41cae31a5
Author: Simon Martin 
Date:   Wed Mar 12 09:09:35 2025 +0100

cobol: Remove unnecesssary CPPFLAGS update and restore MacOS build

The build currently fails on MacOS even when the Cobol front-end and
libgcobol builds are disabled.

The problem is that gcc/cobol/Make-lang.in adds -Iinclude to CPPFLAGS,
which somehow makes clang unhappy about the include order:
  error:  tried including  but didn't find libc++'s
   header. This usually means that your header search paths
  are not configured properly.

It turns out that this addition is unnecessary: simply removing it fixes
the build on MacOS, without impacting the build x86_64-pc-linux-gnu when
configured with --enable-languages=default,cobol.

It feels like there might be more cleanup opportunities there, but they
can be taken care of later.

gcc/cobol/ChangeLog:

* Make-lang.in: Remove unnecessary CPPFLAGS update.

Diff:
---
 gcc/cobol/Make-lang.in | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gcc/cobol/Make-lang.in b/gcc/cobol/Make-lang.in
index cbb31d63c303..9fa3b1cdfdb3 100644
--- a/gcc/cobol/Make-lang.in
+++ b/gcc/cobol/Make-lang.in
@@ -56,7 +56,6 @@ LIB_SOURCE ?= $(srcdir)/../libgcobol
 #
 CPPFLAGS = \
  -std=c++14\
- -Iinclude \
  -I$(BINCLUDE) \
  -I$(LIB_INCLUDE)  \
  -DEXEC_LIB=\"$(prefix)/lib64\"\


[gcc r15-7825] c++: Fix checking assert upon invalid class definition [PR116740]

2025-03-05 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:b3d078220d202094a2b4eaef9b4a5ad1b84d30e6

commit r15-7825-gb3d078220d202094a2b4eaef9b4a5ad1b84d30e6
Author: Simon Martin 
Date:   Wed Mar 5 09:08:57 2025 +0100

c++: Fix checking assert upon invalid class definition [PR116740]

A checking assert triggers upon the following invalid code since
GCC 11:

=== cut here ===
class { a (struct b;
} struct b
=== cut here ===

The problem is that during error recovery, we call
set_identifier_type_value_with_scope for B in the global namespace, and
the checking assert added via r11-7228-g8f93e1b892850b fails.

This patch relaxes that assert to not fail if we've seen a parser error
(it a generalization of another fix done to that checking assert via
r11-7266-g24bf79f1798ad1).

PR c++/116740

gcc/cp/ChangeLog:

* name-lookup.cc (set_identifier_type_value_with_scope): Don't
fail assert with ill-formed input.

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash80.C: New test.

Diff:
---
 gcc/cp/name-lookup.cc| 6 ++
 gcc/testsuite/g++.dg/parse/crash80.C | 7 +++
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index d1abb205bc7f..742e5d289dc9 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -5101,10 +5101,8 @@ set_identifier_type_value_with_scope (tree id, tree 
decl, cp_binding_level *b)
   if (b->kind == sk_namespace)
 /* At namespace scope we should not see an identifier type value.  */
 gcc_checking_assert (!REAL_IDENTIFIER_TYPE_VALUE (id)
-/* We could be pushing a friend underneath a template
-   parm (ill-formed).  */
-|| (TEMPLATE_PARM_P
-(TYPE_NAME (REAL_IDENTIFIER_TYPE_VALUE (id);
+/* But we might end up here with ill-formed input.  */
+|| seen_error ());
   else
 {
   /* Push the current type value, so we can restore it later  */
diff --git a/gcc/testsuite/g++.dg/parse/crash80.C 
b/gcc/testsuite/g++.dg/parse/crash80.C
new file mode 100644
index ..cd9216adf5c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash80.C
@@ -0,0 +1,7 @@
+// PR c++/116740
+// { dg-do "compile" }
+
+class K {
+  int a(struct b; // { dg-error "expected '\\)'" }
+};
+struct b {};


[gcc r15-8009] c++: Look through capture proxy from outer lambda instead of erroring out [PR110584]

2025-03-12 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:90e53ecdbfcc482ad3d0090658427de6d44a5d49

commit r15-8009-g90e53ecdbfcc482ad3d0090658427de6d44a5d49
Author: Simon Martin 
Date:   Wed Mar 12 20:15:39 2025 +0100

c++: Look through capture proxy from outer lambda instead of erroring out 
[PR110584]

We've been rejecting this valid code since r8-4571:

=== cut here ===
void foo (float);
int main () {
  constexpr float x = 0;
  (void) [&] () {
foo (x);
(void) [] () {
  foo (x);
};
  };
}
=== cut here ===

The problem is that when processing X in the inner lambda,
process_outer_var_ref errors out even though it does find the constant
capture from the enclosing lambda.

This patch makes sure that process_outer_var_ref properly looks through
normal capture proxies, if any.

PR c++/110584

gcc/cp/ChangeLog:

* cp-tree.h (strip_normal_capture_proxy): Declare.
* lambda.cc (strip_normal_capture_proxy): New function to look
through normal capture proxies.
(build_capture_proxy): Use it.
* semantics.cc (process_outer_var_ref): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/lambda/lambda-nested10.C: New test.

Diff:
---
 gcc/cp/cp-tree.h   |  1 +
 gcc/cp/lambda.cc   | 14 ++-
 gcc/cp/semantics.cc|  8 ++--
 .../g++.dg/cpp0x/lambda/lambda-nested10.C  | 46 ++
 4 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a839ad6d28ac..07500fa2b21a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8114,6 +8114,7 @@ extern void insert_capture_proxy  (tree);
 extern void insert_pending_capture_proxies (void);
 extern bool is_capture_proxy   (tree);
 extern bool is_normal_capture_proxy (tree);
+extern tree strip_normal_capture_proxy (tree);
 extern bool is_constant_capture_proxy   (tree);
 extern void register_capture_members   (tree);
 extern tree lambda_expr_this_capture(tree, int);
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index da075b988059..ed70bb0ba8e0 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -295,6 +295,17 @@ is_normal_capture_proxy (tree decl)
  && DECL_CAPTURED_VARIABLE (decl));
 }
 
+/* If DECL is a normal capture proxy, return the variable it captures.
+   Otherwise, just return DECL.  */
+
+tree
+strip_normal_capture_proxy (tree decl)
+{
+  while (is_normal_capture_proxy (decl))
+decl = DECL_CAPTURED_VARIABLE (decl);
+  return decl;
+}
+
 /* Returns true iff DECL is a capture proxy for a normal capture
of a constant variable.  */
 
@@ -469,8 +480,7 @@ build_capture_proxy (tree member, tree init)
   STRIP_NOPS (init);
 
   gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL);
-  while (is_normal_capture_proxy (init))
-   init = DECL_CAPTURED_VARIABLE (init);
+  init = strip_normal_capture_proxy (init);
   retrofit_lang_decl (var);
   DECL_CAPTURED_VARIABLE (var) = init;
 }
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7c7d3e3c4326..6e10893262dd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4528,6 +4528,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain, bool odr_use)
   tree lambda_stack = NULL_TREE;
   tree lambda_expr = NULL_TREE;
   tree initializer = convert_from_reference (decl);
+  tree var = strip_normal_capture_proxy (decl);
 
   /* Mark it as used now even if the use is ill-formed.  */
   if (!mark_used (decl, complain))
@@ -4539,9 +4540,6 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain, bool odr_use)
   if (containing_function && LAMBDA_FUNCTION_P (containing_function))
 {
   /* Check whether we've already built a proxy.  */
-  tree var = decl;
-  while (is_normal_capture_proxy (var))
-   var = DECL_CAPTURED_VARIABLE (var);
   tree d = retrieve_local_specialization (var);
 
   if (d && d != decl && is_capture_proxy (d))
@@ -4601,8 +4599,8 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain, bool odr_use)
   /* Only an odr-use of an outer automatic variable causes an
  error, and a constant variable can decay to a prvalue
  constant without odr-use.  So don't complain yet.  */
-  else if (!odr_use && decl_constant_var_p (decl))
-return decl;
+  else if (!odr_use && decl_constant_var_p (var))
+return var;
   else if (lambda_expr)
 {
   if (complain & tf_error)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C 
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
new file mode 100644
index ..aced567c153b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
@@ -0,0 +1,46 @@
+// PR c++/110584
+// { dg-do "run" { target c++11 } }
+

[gcc r13-9448] c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP [PR116681]

2025-03-24 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:73db20707fd60f303313fda3c9245a06037f312a

commit r13-9448-g73db20707fd60f303313fda3c9245a06037f312a
Author: Simon Martin 
Date:   Mon Mar 24 08:25:07 2025 +0100

c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP 
[PR116681]

We currently ICE upon the following testcase when using -ftime-report

=== cut here ===
template < int> using __conditional_t = int;
template < typename _Iter >
concept random_access_iterator = requires { new _Iter; };
template < typename _Iterator >
struct reverse_iterator {
  using iterator_concept =
__conditional_t< random_access_iterator< _Iterator>>;
};
void RemoveBottom() {
  int iter;
  for (reverse_iterator< int > iter;;)
  ;
}
=== cut here ===

The problem is that qualified_namespace_lookup does a plain start() of
the TV_NAME_LOOKUP timer (that asserts that the timer is not already
started). However this timer has already been cond_start()'d in the call
stack - by pushdecl - so the assert fails.

This patch simply ensures that we always conditionally start this timer
(which is done in all other places that use it).

PR c++/116681

gcc/cp/ChangeLog:

* name-lookup.cc (qualified_namespace_lookup): Use an
auto_cond_timer instead of using timevar_start and timevar_stop.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-pr116681.C: New test.

(cherry picked from commit 005f7176e0f457a1e1a7398ddcb4a4972da28c62)

Diff:
---
 gcc/cp/name-lookup.cc  |  3 +--
 gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C | 20 
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 89f28caf183d..16e3cc688f9d 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -6918,10 +6918,9 @@ tree lookup_qualified_name (tree t, const char *p, 
LOOK_want w, bool c)
 static bool
 qualified_namespace_lookup (tree scope, name_lookup *lookup)
 {
-  timevar_start (TV_NAME_LOOKUP);
+  auto_cond_timevar tv (TV_NAME_LOOKUP);
   query_oracle (lookup->name);
   bool found = lookup->search_qualified (ORIGINAL_NAMESPACE (scope));
-  timevar_stop (TV_NAME_LOOKUP);
   return found;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C
new file mode 100644
index ..f1b47797f1ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C
@@ -0,0 +1,20 @@
+// PR c++/116681
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-ftime-report" }
+// { dg-allow-blank-lines-in-output 1 }
+// { dg-prune-output "Time variable" }
+// { dg-prune-output "k" }
+// { dg-prune-output "\[0-9\]+%" }
+
+template < int> using __conditional_t = int;
+template < typename _Iter >
+concept random_access_iterator = requires { new _Iter; };
+template < typename _Iterator > struct reverse_iterator {
+  using iterator_concept = __conditional_t< random_access_iterator< _Iterator 
>>;
+};
+void RemoveBottom()
+{
+  int iter;
+  for (reverse_iterator< int > iter;;)
+  ;
+}


[gcc r14-11442] c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP [PR116681]

2025-03-24 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:8bac22817192349cad15c88e01a73798e2a783ad

commit r14-11442-g8bac22817192349cad15c88e01a73798e2a783ad
Author: Simon Martin 
Date:   Mon Mar 24 08:15:54 2025 +0100

c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP 
[PR116681]

We currently ICE upon the following testcase when using -ftime-report

=== cut here ===
template < int> using __conditional_t = int;
template < typename _Iter >
concept random_access_iterator = requires { new _Iter; };
template < typename _Iterator >
struct reverse_iterator {
  using iterator_concept =
__conditional_t< random_access_iterator< _Iterator>>;
};
void RemoveBottom() {
  int iter;
  for (reverse_iterator< int > iter;;)
  ;
}
=== cut here ===

The problem is that qualified_namespace_lookup does a plain start() of
the TV_NAME_LOOKUP timer (that asserts that the timer is not already
started). However this timer has already been cond_start()'d in the call
stack - by pushdecl - so the assert fails.

This patch simply ensures that we always conditionally start this timer
(which is done in all other places that use it).

PR c++/116681

gcc/cp/ChangeLog:

* name-lookup.cc (qualified_namespace_lookup): Use an
auto_cond_timer instead of using timevar_start and timevar_stop.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-pr116681.C: New test.

(cherry picked from commit 005f7176e0f457a1e1a7398ddcb4a4972da28c62)

Diff:
---
 gcc/cp/name-lookup.cc  |  3 +--
 gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C | 20 
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 309f8fdadcb3..2e203e5ca0c8 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -7333,10 +7333,9 @@ tree lookup_qualified_name (tree t, const char *p, 
LOOK_want w, bool c)
 static bool
 qualified_namespace_lookup (tree scope, name_lookup *lookup)
 {
-  timevar_start (TV_NAME_LOOKUP);
+  auto_cond_timevar tv (TV_NAME_LOOKUP);
   query_oracle (lookup->name);
   bool found = lookup->search_qualified (ORIGINAL_NAMESPACE (scope));
-  timevar_stop (TV_NAME_LOOKUP);
   return found;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C
new file mode 100644
index ..f1b47797f1ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C
@@ -0,0 +1,20 @@
+// PR c++/116681
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-ftime-report" }
+// { dg-allow-blank-lines-in-output 1 }
+// { dg-prune-output "Time variable" }
+// { dg-prune-output "k" }
+// { dg-prune-output "\[0-9\]+%" }
+
+template < int> using __conditional_t = int;
+template < typename _Iter >
+concept random_access_iterator = requires { new _Iter; };
+template < typename _Iterator > struct reverse_iterator {
+  using iterator_concept = __conditional_t< random_access_iterator< _Iterator 
>>;
+};
+void RemoveBottom()
+{
+  int iter;
+  for (reverse_iterator< int > iter;;)
+  ;
+}


[gcc r14-11445] c++: Don't replace INDIRECT_REFs by a const capture proxy too eagerly [PR117504]

2025-03-25 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:f078a613bf85eff138c2567b599779dee6ae4b22

commit r14-11445-gf078a613bf85eff138c2567b599779dee6ae4b22
Author: Simon Martin 
Date:   Tue Mar 25 07:08:16 2025 +0100

c++: Don't replace INDIRECT_REFs by a const capture proxy too eagerly 
[PR117504]

We have been miscompiling the following valid code since GCC8, and
r8-3497-g281e6c1d8f1b4c

=== cut here ===
struct span {
  span (const int (&__first)[1]) : _M_ptr (__first) {}
  int operator[] (long __i) { return _M_ptr[__i]; }
  const int *_M_ptr;
};
void foo () {
  constexpr int a_vec[]{1};
  auto vec{[&a_vec]() -> span { return a_vec; }()};
}
=== cut here ===

The problem is that perform_implicit_conversion_flags (via
mark_rvalue_use) replaces "a_vec" in the return statement by a
CONSTRUCTOR representing a_vec's constant value, and then takes its
address when invoking span's constructor. So we end up with an instance
that points to garbage instead of a_vec's storage.

As per Jason's suggestion, this patch simply removes the calls to
mark_*_use from perform_implicit_conversion_flags, which fixes the PR.

PR c++/117504

gcc/cp/ChangeLog:

* call.cc (perform_implicit_conversion_flags): Don't call
mark_{l,r}value_use.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-117504.C: New test.
* g++.dg/cpp2a/constexpr-117504a.C: New test.

(cherry picked from commit fdf846fdddcc0467b9f025757f081c5d54319d08)

Diff:
---
 gcc/cp/call.cc |  5 ---
 gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C  | 60 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C | 12 ++
 3 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index f580c3f5442f..180afa6d053d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13663,11 +13663,6 @@ perform_implicit_conversion_flags (tree type, tree 
expr,
   conversion *conv;
   location_t loc = cp_expr_loc_or_input_loc (expr);
 
-  if (TYPE_REF_P (type))
-expr = mark_lvalue_use (expr);
-  else
-expr = mark_rvalue_use (expr);
-
   if (error_operand_p (expr))
 return error_mark_node;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C
new file mode 100644
index ..290d3dfd61e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504.C
@@ -0,0 +1,60 @@
+// PR c++/117504 - Initial report
+// { dg-do "run" { target c++20 } }
+
+struct span {
+  span (const int (&__first)[1]) : _M_ptr (__first) {}
+  int operator[] (long __i) { return _M_ptr[__i]; }
+  const int *_M_ptr;
+};
+
+constexpr int a_global_vec[]{1};
+span myFunctor() {
+  return a_global_vec;
+}
+
+int main() {
+  constexpr int a_vec[]{1};
+
+  //
+  // This PR's case, that used to be miscompiled.
+  //
+  auto lambda_1 = [&a_vec] () -> span { return a_vec; };
+  auto vec_1 { lambda_1 () };
+  if (vec_1[0] != 1)
+__builtin_abort ();
+
+  // Variant that used to be miscompiled as well.
+  auto lambda_2 = [&] () -> span { return a_vec; };
+  auto vec_2 { lambda_2 () };
+  if (vec_2[0] != 1)
+__builtin_abort ();
+
+  //
+  // Related cases that worked already.
+  //
+  auto lambda_3 = [&a_vec] () /* -> span */ { return a_vec; };
+  auto vec_3 { lambda_3 () };
+  if (vec_3[0] != 1)
+__builtin_abort ();
+
+  auto lambda_4 = [&] () /* -> span */ { return a_vec; };
+  auto vec_4 { lambda_4 () };
+  if (vec_4[0] != 1)
+__builtin_abort ();
+
+  const int (&vec_5)[1] = a_vec;
+  if (vec_5[0] != 1)
+__builtin_abort ();
+  
+  span vec_6 (a_vec);
+  if (vec_6[0] != 1)
+__builtin_abort ();
+
+  auto vec_7 = myFunctor ();
+  if (vec_7[0] != 1)
+__builtin_abort ();
+
+  const int (&vec_8)[1] { a_vec };
+  if (vec_8[0] != 1)
+__builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C
new file mode 100644
index ..f6d4dc8cbc53
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-117504a.C
@@ -0,0 +1,12 @@
+// PR c++/117504 - ICE discovered by ppalka@ when reducing.
+// { dg-do "compile" { target c++20 } }
+
+struct span {
+  span (const int* __first) : _M_ptr (__first) {}
+  int operator[] (long __i) { return _M_ptr[__i]; }
+  const int *_M_ptr;
+};
+int main() {
+  constexpr int a_vec[]{1};
+  auto vec { [&a_vec]() -> span { return a_vec; } () };
+}


[gcc r16-639] c++: Add testcase for issue fixed in GCC 15 [PR120126]

2025-05-14 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:7ec6f7da7064a6ab9f443e3a03d4401d8bc5ae23

commit r16-639-g7ec6f7da7064a6ab9f443e3a03d4401d8bc5ae23
Author: Simon Martin 
Date:   Wed May 14 20:29:57 2025 +0200

c++: Add testcase for issue fixed in GCC 15 [PR120126]

Patrick noticed that this PR's testcase has been fixed by the patch for
PR c++/114292 (r15-7238-gceabea405ffdc8), more specifically the part
that walks the type of DECL_EXPR DECLs.

This simply adds the case to the testsuite.

PR c++/120126

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/lambda/lambda-ice33.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice33.C | 12 
 1 file changed, 12 insertions(+)

diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice33.C 
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice33.C
new file mode 100644
index ..856428635300
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice33.C
@@ -0,0 +1,12 @@
+// PR c++/120126
+// { dg-do compile { target c++11 } }
+
+template 
+int sum(Args... args) {
+  return [args...] { // { dg-error "parameter packs not expanded with" }
+typename decltype(args)::type temp;
+  };
+}
+int main() {
+  sum(1, 10);
+}