[gcc r15-3980] c++: concept in default argument [PR109859]

2024-09-30 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:4bcfaaed25b1b8ecc81f6a28d9ca76f00870dedf

commit r15-3980-g4bcfaaed25b1b8ecc81f6a28d9ca76f00870dedf
Author: Marek Polacek 
Date:   Wed Sep 18 15:44:31 2024 -0400

c++: concept in default argument [PR109859]

1) We're hitting the assert in cp_parser_placeholder_type_specifier.
It says that if it turns out to be false, we should do error() instead.
Do so, then.

2) lambda-targ8.C should compile fine, though.  The problem was that
local_variables_forbidden_p wasn't cleared when we're about to parse
the optional template-parameter-list for a lambda in a default argument.

PR c++/109859

gcc/cp/ChangeLog:

* parser.cc (cp_parser_lambda_declarator_opt): Temporarily clear
local_variables_forbidden_p.
(cp_parser_placeholder_type_specifier): Turn an assert into an
error.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-defarg3.C: New test.
* g++.dg/cpp2a/lambda-targ8.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/parser.cc  |  9 +++--
 gcc/testsuite/g++.dg/cpp2a/concepts-defarg3.C |  8 
 gcc/testsuite/g++.dg/cpp2a/lambda-targ8.C | 10 ++
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f50534f5f395..0944827d777b 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -11891,6 +11891,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, 
tree lambda_expr)
 "lambda templates are only available with "
 "%<-std=c++20%> or %<-std=gnu++20%>");
 
+  /* Even though the whole lambda may be a default argument, its
+template-parameter-list is a context where it's OK to create
+new parameters.  */
+  auto lvf = make_temp_override (parser->local_variables_forbidden_p, 0u);
+
   cp_lexer_consume_token (parser->lexer);
 
   template_param_list = cp_parser_template_parameter_list (parser);
@@ -20989,8 +20994,8 @@ cp_parser_placeholder_type_specifier (cp_parser 
*parser, location_t loc,
   /* In a default argument we may not be creating new parameters.  */
   if (parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN)
{
- /* If this assert turns out to be false, do error() instead.  */
- gcc_assert (tentative);
+ if (!tentative)
+   error_at (loc, "invalid use of concept-name %qD", con);
  return error_mark_node;
}
   return build_constrained_parameter (con, proto, args);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-defarg3.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-defarg3.C
new file mode 100644
index ..6fe82f91e434
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-defarg3.C
@@ -0,0 +1,8 @@
+// PR c++/109859
+// { dg-do compile { target c++20 } }
+
+template
+concept C = true;
+
+template  // { dg-error "invalid use of concept-name .C." }
+int f();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ8.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ8.C
new file mode 100644
index ..3685b0ef880b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ8.C
@@ -0,0 +1,10 @@
+// PR c++/109859
+// { dg-do compile { target c++20 } }
+
+template
+concept A = true;
+
+template {}>
+int x;
+
+void g() { (void) x<>; }


[gcc r15-3933] c++: ICE with structured bindings and m-d array [PR102594]

2024-09-27 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:96e0370f4daef29b918aafcff68c7f5e4ef397fd

commit r15-3933-g96e0370f4daef29b918aafcff68c7f5e4ef397fd
Author: Marek Polacek 
Date:   Thu Sep 5 16:45:32 2024 -0400

c++: ICE with structured bindings and m-d array [PR102594]

We ICE in decay_conversion with this test:

  struct S {
S() {}
  };
  S arr[1][1];
  auto [m](arr3);

But not when the last line is:

  auto [n] = arr3;

Therefore the difference is between copy- and direct-init.  In
particular, in build_vec_init we have:

  if (direct_init)
from = build_tree_list (NULL_TREE, from);

and then we call build_vec_init again with init==from.  Then
decay_conversion gets the TREE_LIST and it crashes.

build_aggr_init has:

  /* Wrap the initializer in a CONSTRUCTOR so that 
build_vec_init
 recognizes it as direct-initialization.  */
  init = build_constructor_single (init_list_type_node,
   NULL_TREE, init);
  CONSTRUCTOR_IS_DIRECT_INIT (init) = true;

so I propose to do the same in build_vec_init.

PR c++/102594

gcc/cp/ChangeLog:

* init.cc (build_vec_init): Build up a CONSTRUCTOR to signal
direct-initialization rather than a TREE_LIST.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/decomp61.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/init.cc|  8 +++-
 gcc/testsuite/g++.dg/cpp1z/decomp61.C | 28 
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index be7fdb40dd6c..f785015e4774 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4958,7 +4958,13 @@ build_vec_init (tree base, tree maxindex, tree init,
  if (xvalue)
from = move (from);
  if (direct_init)
-   from = build_tree_list (NULL_TREE, from);
+   {
+ /* Wrap the initializer in a CONSTRUCTOR so that
+build_vec_init recognizes it as direct-initialization.  */
+ from = build_constructor_single (init_list_type_node,
+  NULL_TREE, from);
+ CONSTRUCTOR_IS_DIRECT_INIT (from) = true;
+   }
}
  else
from = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp61.C 
b/gcc/testsuite/g++.dg/cpp1z/decomp61.C
new file mode 100644
index ..ad0a20c1addd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp61.C
@@ -0,0 +1,28 @@
+// PR c++/102594
+// { dg-do compile { target c++17 } }
+
+struct S {
+  S() {}
+};
+S arr1[2];
+S arr2[2][1];
+S arr3[1][1];
+auto [m](arr3);
+auto [n] = arr3;
+
+struct X {
+  int i;
+};
+
+void
+g (X x)
+{
+  auto [a, b](arr2);
+  auto [c, d] = arr2;
+  auto [e, f] = (arr2);
+  auto [i, j](arr1);
+  auto [k, l] = arr1;
+  auto [m, n] = (arr1);
+  auto [z] = x;
+  auto [y](x);
+}


[gcc r15-3905] c++: tweak for -Wrange-loop-construct [PR116731]

2024-09-26 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:6ac4e2f4b2ca9980670e7d3815a9140730df1005

commit r15-3905-g6ac4e2f4b2ca9980670e7d3815a9140730df1005
Author: Marek Polacek 
Date:   Tue Sep 17 16:58:37 2024 -0400

c++: tweak for -Wrange-loop-construct [PR116731]

This PR reports that the warning would be better off using a check
for trivially constructible rather than trivially copyable.

LLVM accepted a similar fix:
https://github.com/llvm/llvm-project/issues/47355

PR c++/116731

gcc/cp/ChangeLog:

* parser.cc (warn_for_range_copy): Check if TYPE is trivially
constructible, not copyable.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wrange-loop-construct3.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/parser.cc   |  8 +--
 gcc/testsuite/g++.dg/warn/Wrange-loop-construct3.C | 57 ++
 2 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 6d3be94bf448..f50534f5f395 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -14394,11 +14394,13 @@ warn_for_range_copy (tree decl, tree expr)
   else if (!CP_TYPE_CONST_P (type))
 return;
 
-  /* Since small trivially copyable types are cheap to copy, we suppress the
- warning for them.  64B is a common size of a cache line.  */
+  /* Since small trivially constructible types are cheap to construct, we
+ suppress the warning for them.  64B is a common size of a cache line.  */
+  tree vec = make_tree_vec (1);
+  TREE_VEC_ELT (vec, 0) = TREE_TYPE (expr);
   if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
   || (tree_to_uhwi (TYPE_SIZE_UNIT (type)) <= 64
- && trivially_copyable_p (type)))
+ && is_trivially_xible (INIT_EXPR, type, vec)))
 return;
 
   /* If we can initialize a reference directly, suggest that to avoid the
diff --git a/gcc/testsuite/g++.dg/warn/Wrange-loop-construct3.C 
b/gcc/testsuite/g++.dg/warn/Wrange-loop-construct3.C
new file mode 100644
index ..3d9d0c9088e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wrange-loop-construct3.C
@@ -0,0 +1,57 @@
+// PR c++/116731
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wrange-loop-construct" }
+
+void
+f0 ()
+{
+  struct S {
+char a[64];
+S& operator=(const S&) { return *this; };
+  };
+
+  S arr[8];
+  for (const auto r : arr)
+(void) r;
+}
+
+void
+f1 ()
+{
+  struct S {
+char a[65];
+S& operator=(const S&) { return *this; };
+  };
+
+  S arr[8];
+  for (const auto r : arr) // { dg-warning "creates a copy" }
+(void) r;
+}
+
+void
+f2 ()
+{
+  struct S {
+char a[64];
+S& operator=(const S&) { return *this; };
+~S() { }
+  };
+
+  S arr[8];
+  for (const auto r : arr) // { dg-warning "creates a copy" }
+(void) r;
+}
+
+void
+f3 ()
+{
+  struct S {
+char a[65];
+S& operator=(const S&) { return *this; };
+~S() { }
+  };
+
+  S arr[8];
+  for (const auto r : arr) // { dg-warning "creates a copy" }
+(void) r;
+}


[gcc r15-3863] c++: use TARGET_EXPR accessors

2024-09-25 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:1fea6f82489006cfec3171f77bde8b5ed3527616

commit r15-3863-g1fea6f82489006cfec3171f77bde8b5ed3527616
Author: Marek Polacek 
Date:   Tue Sep 24 17:54:04 2024 -0400

c++: use TARGET_EXPR accessors

While futzing around with PR116416 I noticed that we can use
the _SLOT and _INITIAL macros to make the code more readable.

gcc/c-family/ChangeLog:

* c-pretty-print.cc (c_pretty_printer::primary_expression): Use
TARGET_EXPR accessors.
(c_pretty_printer::expression): Likewise.

gcc/cp/ChangeLog:

* coroutines.cc (build_co_await): Use TARGET_EXPR accessors.
(finish_co_yield_expr): Likewise.
(register_awaits): Likewise.
(tmp_target_expr_p): Likewise.
(flatten_await_stmt): Likewise.
* error.cc (dump_expr): Likewise.
* semantics.cc (finish_omp_target_clauses): Likewise.
* tree.cc (bot_manip): Likewise.
(cp_tree_equal): Likewise.
* typeck.cc (cxx_mark_addressable): Likewise.
(cp_build_compound_expr): Likewise.
(cp_build_modify_expr): Likewise.
(check_return_expr): Likewise.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/c-family/c-pretty-print.cc | 10 +-
 gcc/cp/coroutines.cc   | 18 +-
 gcc/cp/error.cc|  4 ++--
 gcc/cp/semantics.cc|  2 +-
 gcc/cp/tree.cc | 27 ++-
 gcc/cp/typeck.cc   | 12 ++--
 6 files changed, 37 insertions(+), 36 deletions(-)

diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc
index 26038818d759..0c764aecc3de 100644
--- a/gcc/c-family/c-pretty-print.cc
+++ b/gcc/c-family/c-pretty-print.cc
@@ -1376,14 +1376,14 @@ c_pretty_printer::primary_expression (tree e)
   pp_c_ws_string (this, "__builtin_memcpy");
   pp_c_left_paren (this);
   pp_ampersand (this);
-  primary_expression (TREE_OPERAND (e, 0));
+  primary_expression (TARGET_EXPR_SLOT (e));
   pp_separate_with (this, ',');
   pp_ampersand (this);
-  initializer (TREE_OPERAND (e, 1));
-  if (TREE_OPERAND (e, 2))
+  initializer (TARGET_EXPR_INITIAL (e));
+  if (TARGET_EXPR_CLEANUP (e))
{
  pp_separate_with (this, ',');
- expression (TREE_OPERAND (e, 2));
+ expression (TARGET_EXPR_CLEANUP (e));
}
   pp_c_right_paren (this);
   break;
@@ -2838,7 +2838,7 @@ c_pretty_printer::expression (tree e)
   break;
 
 case TARGET_EXPR:
-  postfix_expression (TREE_OPERAND (e, 1));
+  postfix_expression (TARGET_EXPR_INITIAL (e));
   break;
 
 case BIND_EXPR:
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 70c9094d1d19..4c7ea1dd3216 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1258,7 +1258,7 @@ build_co_await (location_t loc, tree a, 
suspend_point_kind suspend_kind,
   if (TREE_CODE (awrs_call) == TARGET_EXPR)
 {
   te = awrs_call;
-  awrs_call = TREE_OPERAND (awrs_call, 1);
+  awrs_call = TARGET_EXPR_INITIAL (awrs_call);
 }
   TREE_VEC_ELT (awaiter_calls, 2) = awrs_call; /* await_resume().  */
 
@@ -1447,9 +1447,9 @@ finish_co_yield_expr (location_t kw, tree expr)
 its contained await.  Otherwise, just build the CO_YIELD_EXPR.  */
   if (TREE_CODE (op) == TARGET_EXPR)
{
- tree t = TREE_OPERAND (op, 1);
+ tree t = TARGET_EXPR_INITIAL (op);
  t = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (t), expr, t);
- TREE_OPERAND (op, 1) = t;
+ TARGET_EXPR_INITIAL (op) = t;
}
   else
op = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (op), expr, op);
@@ -2711,7 +2711,7 @@ register_awaits (tree *stmt, int *, void *d)
   tree v = TREE_OPERAND (aw_expr, 3);
   tree o = TREE_VEC_ELT (v, 1);
   if (TREE_CODE (o) == TARGET_EXPR)
-TREE_VEC_ELT (v, 1) = get_target_expr (TREE_OPERAND (o, 1));
+TREE_VEC_ELT (v, 1) = get_target_expr (TARGET_EXPR_INITIAL (o));
   return NULL_TREE;
 }
 
@@ -2734,7 +2734,7 @@ tmp_target_expr_p (tree t)
 {
   if (TREE_CODE (t) != TARGET_EXPR)
 return false;
-  tree v = TREE_OPERAND (t, 0);
+  tree v = TARGET_EXPR_SLOT (t);
   if (!DECL_ARTIFICIAL (v))
 return false;
   if (DECL_NAME (v))
@@ -2941,7 +2941,7 @@ flatten_await_stmt (var_nest_node *n, hash_set 
*promoted,
{
  temps_used->add (inner);
  gcc_checking_assert
-   (TREE_CODE (TREE_OPERAND (inner, 1)) != COND_EXPR);
+   (TREE_CODE (TARGET_EXPR_INITIAL (inner)) != COND_EXPR);
}
}
break;
@@ -2972,7 +2972,7 @@ flatten_await_stmt (var_nest_node *n, hash_set 
*promoted,
  free (buf);
  bool already_present = promoted->add (var);
  gcc_checking_assert (!already_present);
- tree i

[gcc r15-3812] c++: diagnose this specifier in requires expr [PR116798]

2024-09-23 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:4700ad1c78ccd7767f846802fca148b2ea9a1852

commit r15-3812-g4700ad1c78ccd7767f846802fca148b2ea9a1852
Author: Marek Polacek 
Date:   Mon Sep 23 12:19:40 2024 -0400

c++: diagnose this specifier in requires expr [PR116798]

We don't detect an explicit object parameter in a requires expression.
We can get there by way of requires-expression -> requirement-parameter-list
-> parameter-declaration-clause -> ... -> parameter-declaration with
this[opt].  But [dcl.fct]/5 doesn't allow an explicit object parameter
in this context.  So let's fix it like r14-9033 and not like r14-8832.

PR c++/116798

gcc/cp/ChangeLog:

* parser.cc (cp_parser_parameter_declaration): Detect an explicit
object parameter in a requires expression.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/explicit-obj-diagnostics12.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/parser.cc| 11 ---
 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics12.C | 10 ++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 4dd9474cf609..dbc607027dfb 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -25982,10 +25982,15 @@ cp_parser_parameter_declaration (cp_parser *parser,
 
   bool xobj_param_p
 = decl_spec_seq_has_spec_p (&decl_specifiers, ds_this);
-  if (xobj_param_p && template_parm_p)
+  if (xobj_param_p
+  && (template_parm_p || current_binding_level->requires_expression))
 {
-  error_at (decl_specifiers.locations[ds_this],
-   "% specifier in template parameter declaration");
+  if (template_parm_p)
+   error_at (decl_specifiers.locations[ds_this],
+ "% specifier in template parameter declaration");
+  else
+   error_at (decl_specifiers.locations[ds_this],
+ "% specifier in a requires-expression parameter");
   xobj_param_p = false;
   decl_specifiers.locations[ds_this] = 0;
 }
diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics12.C 
b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics12.C
new file mode 100644
index ..ec0aced0fd9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics12.C
@@ -0,0 +1,10 @@
+// PR c++/116798
+// { dg-do compile { target c++23 } }
+
+template
+concept C = requires(this T u,   // { dg-error "'this' specifier in a 
requires-expression parameter" }
+this T v) {  // { dg-error "'this' specifier in a 
requires-expression parameter" }
+u + v;
+};
+
+static_assert(C);


[gcc r15-3722] c-family: regenerate c.opt.urls

2024-09-19 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:91da9e3b5486875efbdb7428d63c3a0fa42508a9

commit r15-3722-g91da9e3b5486875efbdb7428d63c3a0fa42508a9
Author: Marek Polacek 
Date:   Thu Sep 19 18:55:18 2024 -0400

c-family: regenerate c.opt.urls

I forgot again.

gcc/c-family/ChangeLog:

* c.opt.urls: Regenerate.

Diff:
---
 gcc/c-family/c.opt.urls | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls
index e40b8e5c3a0d..2f1e9f95271b 100644
--- a/gcc/c-family/c.opt.urls
+++ b/gcc/c-family/c.opt.urls
@@ -280,6 +280,9 @@ 
UrlSuffix(gcc/Warning-Options.html#index-Wdeclaration-after-statement)
 Wdeclaration-missing-parameter-type
 UrlSuffix(gcc/Warning-Options.html#index-Wdeclaration-missing-parameter-type)
 
+Wdefaulted-function-deleted
+UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdefaulted-function-deleted)
+
 Wdelete-incomplete
 UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdelete-incomplete)


[gcc r15-3721] c++: deleting explicitly-defaulted functions [PR116162]

2024-09-19 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:a2746e4347076ea48f4aeb28e13e6337ff7799ad

commit r15-3721-ga2746e4347076ea48f4aeb28e13e6337ff7799ad
Author: Marek Polacek 
Date:   Mon Sep 9 14:23:33 2024 -0400

c++: deleting explicitly-defaulted functions [PR116162]

This PR points out the we're not implementing [dcl.fct.def.default]
properly.  Consider e.g.

  struct C {
 C(const C&&) = default;
  };

where we wrongly emit an error, but the move ctor should be just =deleted.
According to [dcl.fct.def.default], if the type of the special member
function differs from the type of the corresponding special member function
that would have been implicitly declared in a way other than as allowed
by 2.1-4, the function is defined as deleted.  There's an exception for
assignment operators in which case the program is ill-formed.

clang++ has a warning for when we delete an explicitly-defaulted function
so this patch adds it too.

When the code is ill-formed, we emit an error in all modes.  Otherwise,
we emit a pedwarn in C++17 and a warning in C++20.

PR c++/116162

gcc/c-family/ChangeLog:

* c.opt (Wdefaulted-function-deleted): New.

gcc/cp/ChangeLog:

* class.cc (check_bases_and_members): Don't set DECL_DELETED_FN 
here,
leave it to defaulted_late_check.
* cp-tree.h (maybe_delete_defaulted_fn): Declare.
(defaulted_late_check): Add a tristate parameter.
* method.cc (maybe_delete_defaulted_fn): New.
(defaulted_late_check): Add a tristate parameter.  Call
maybe_delete_defaulted_fn instead of giving an error.

gcc/ChangeLog:

* doc/invoke.texi: Document -Wdefaulted-function-deleted.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/defaulted15.C: Add dg-warning/dg-error.
* g++.dg/cpp0x/defaulted51.C: Likewise.
* g++.dg/cpp0x/defaulted52.C: Likewise.
* g++.dg/cpp0x/defaulted53.C: Likewise.
* g++.dg/cpp0x/defaulted54.C: Likewise.
* g++.dg/cpp0x/defaulted56.C: Likewise.
* g++.dg/cpp0x/defaulted57.C: Likewise.
* g++.dg/cpp0x/defaulted58.C: Likewise.
* g++.dg/cpp0x/defaulted59.C: Likewise.
* g++.dg/cpp0x/defaulted63.C: New test.
* g++.dg/cpp0x/defaulted64.C: New test.
* g++.dg/cpp0x/defaulted65.C: New test.
* g++.dg/cpp0x/defaulted66.C: New test.
* g++.dg/cpp0x/defaulted67.C: New test.
* g++.dg/cpp0x/defaulted68.C: New test.
* g++.dg/cpp0x/defaulted69.C: New test.
* g++.dg/cpp23/defaulted1.C: New test.

Diff:
---
 gcc/c-family/c.opt   |  4 ++
 gcc/cp/class.cc  | 27 +++--
 gcc/cp/cp-tree.h |  3 +-
 gcc/cp/method.cc | 98 
 gcc/doc/invoke.texi  |  9 +++
 gcc/testsuite/g++.dg/cpp0x/defaulted15.C |  3 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted51.C |  2 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted52.C |  2 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted53.C |  3 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted54.C |  1 +
 gcc/testsuite/g++.dg/cpp0x/defaulted56.C |  6 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted57.C |  6 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted58.C |  1 +
 gcc/testsuite/g++.dg/cpp0x/defaulted59.C |  3 +-
 gcc/testsuite/g++.dg/cpp0x/defaulted63.C | 39 +
 gcc/testsuite/g++.dg/cpp0x/defaulted64.C | 27 +
 gcc/testsuite/g++.dg/cpp0x/defaulted65.C | 25 
 gcc/testsuite/g++.dg/cpp0x/defaulted66.C | 35 
 gcc/testsuite/g++.dg/cpp0x/defaulted67.C | 23 
 gcc/testsuite/g++.dg/cpp0x/defaulted68.C | 35 
 gcc/testsuite/g++.dg/cpp0x/defaulted69.C | 24 
 gcc/testsuite/g++.dg/cpp23/defaulted1.C  | 23 
 22 files changed, 359 insertions(+), 40 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index ec23249c9592..98a35f043c76 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -629,6 +629,10 @@ Wdeclaration-missing-parameter-type
 C ObjC Var(warn_declaration_missing_parameter) Warning Init(1)
 Warn for missing parameter types in function declarations.
 
+Wdefaulted-function-deleted
+C++ ObjC++ Var(warn_defaulted_fn_deleted) Init(1) Warning
+Warn when an explicitly defaulted function is deleted.
+
 Wdelete-incomplete
 C++ ObjC++ Var(warn_delete_incomplete) Init(1) Warning
 Warn when deleting a pointer to incomplete type.
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 950d83b0ea43..646072d4f202 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -6488,27 +6488,14 @@ check_bases_and_members (tree t)
   for (fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn))
 if (DECL_DECLARES_FUNCTION_P (fn)
&& !DECL_ARTIFICIAL (fn)
-   && DECL_DEFAULTED_IN_CLASS_P (fn))
-  {
+   && 

[gcc r15-3674] c++: fix constexpr cast from void* diag issue [PR116741]

2024-09-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d6d8445c85509b66a59aa6247ad7b2cfeab17725

commit r15-3674-gd6d8445c85509b66a59aa6247ad7b2cfeab17725
Author: Marek Polacek 
Date:   Tue Sep 17 14:34:30 2024 -0400

c++: fix constexpr cast from void* diag issue [PR116741]

The result of build_fold_indirect_ref can be a COMPONENT_REF in
which case using DECL_SOURCE_LOCATION will crash.  Look at its op1
instead.

PR c++/116741

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_constant_expression) : 
If
the result of build_fold_indirect_ref is a COMPONENT_REF, use its 
op1.
Check DECL_P before calling inform.

gcc/testsuite/ChangeLog:

* g++.dg/cpp26/constexpr-voidptr4.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constexpr.cc |  7 --
 gcc/testsuite/g++.dg/cpp26/constexpr-voidptr4.C | 29 +
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c3668b0d7d3f..f6fd059be466 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8201,8 +8201,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
  TREE_TYPE (op), TREE_TYPE (TREE_TYPE (sop)),
  TREE_TYPE (type));
tree obj = build_fold_indirect_ref (sop);
-   inform (DECL_SOURCE_LOCATION (obj),
-   "pointed-to object declared here");
+   if (TREE_CODE (obj) == COMPONENT_REF)
+ obj = TREE_OPERAND (obj, 1);
+   if (DECL_P (obj))
+ inform (DECL_SOURCE_LOCATION (obj),
+ "pointed-to object declared here");
  }
*non_constant_p = true;
return t;
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr4.C 
b/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr4.C
new file mode 100644
index ..53563c928f27
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr4.C
@@ -0,0 +1,29 @@
+// PR c++/116741
+// { dg-do compile { target c++26 } }
+
+struct S {
+  int foo;// { dg-message "pointed-to object" }
+};
+
+struct S2 {
+  int foo;// { dg-message "pointed-to object" }
+};
+
+struct X {
+  S2 s;
+};
+
+constexpr float f1() {
+  S s;
+  void* p = &s.foo;
+  return *static_cast(p); // { dg-error "not allowed in a constant 
expression" }
+}
+
+constexpr float f2() {
+  X x;
+  void* p = &x.s.foo;
+  return *static_cast(p); // { dg-error "not allowed in a constant 
expression" }
+}
+
+constexpr auto x1 = f1();
+constexpr auto x2 = f2();


[gcc r15-3673] c++: ICE with -Wtautological-compare in template [PR116534]

2024-09-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:7ca486889b1b1c7e7bcbbca3b6caa103294ec07d

commit r15-3673-g7ca486889b1b1c7e7bcbbca3b6caa103294ec07d
Author: Marek Polacek 
Date:   Thu Aug 29 10:40:50 2024 -0400

c++: ICE with -Wtautological-compare in template [PR116534]

Pre r14-4793, we'd call warn_tautological_cmp -> operand_equal_p
with operands wrapped in NON_DEPENDENT_EXPR, which works, since
o_e_p bails for codes it doesn't know.  But now we pass operands
not encapsulated in NON_DEPENDENT_EXPR, and crash, because the
template tree for &a[x] has null DECL_FIELD_OFFSET.

This patch extends r12-7797 to cover the case when DECL_FIELD_OFFSET
is null.

PR c++/116534

gcc/ChangeLog:

* fold-const.cc (operand_compare::operand_equal_p): If either
field's DECL_FIELD_OFFSET is null, compare the fields with ==.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wtautological-compare4.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/fold-const.cc  | 12 +---
 gcc/testsuite/g++.dg/warn/Wtautological-compare4.C | 21 +
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 70db16759d04..0578f42ac0c5 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -3601,9 +3601,15 @@ operand_compare::operand_equal_p (const_tree arg0, 
const_tree arg1,
 
/* Non-FIELD_DECL operands can appear in C++ templates.  */
if (TREE_CODE (field0) != FIELD_DECL
-   || TREE_CODE (field1) != FIELD_DECL
-   || !operand_equal_p (DECL_FIELD_OFFSET (field0),
-DECL_FIELD_OFFSET (field1), flags)
+   || TREE_CODE (field1) != FIELD_DECL)
+ return false;
+
+   if (!DECL_FIELD_OFFSET (field0)
+   || !DECL_FIELD_OFFSET (field1))
+ return field0 == field1;
+
+   if (!operand_equal_p (DECL_FIELD_OFFSET (field0),
+ DECL_FIELD_OFFSET (field1), flags)
|| !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0),
 DECL_FIELD_BIT_OFFSET (field1),
 flags))
diff --git a/gcc/testsuite/g++.dg/warn/Wtautological-compare4.C 
b/gcc/testsuite/g++.dg/warn/Wtautological-compare4.C
new file mode 100644
index ..96308f49a429
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wtautological-compare4.C
@@ -0,0 +1,21 @@
+// PR c++/116534
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+template 
+struct Test {
+bool foo(unsigned x, unsigned y) {
+bool test = &a[x] == &b[y];
+   return test;
+}
+unsigned *a;
+unsigned *b;
+};
+
+void
+g ()
+{
+  Test t;
+  t.foo (0u, 1u);
+  t.foo (0u, 0u);
+}


[gcc r12-10713] c++: crash with anon VAR_DECL [PR116676]

2024-09-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:9046f9aeae0f926e7365d39809a80855e7dc184a

commit r12-10713-g9046f9aeae0f926e7365d39809a80855e7dc184a
Author: Marek Polacek 
Date:   Mon Sep 16 16:42:38 2024 -0400

c++: crash with anon VAR_DECL [PR116676]

r12-3495 added maybe_warn_about_constant_value which will crash if
it gets a nameless VAR_DECL, which is what happens in this PR.

We created this VAR_DECL in cp_parser_decomposition_declaration.

PR c++/116676

gcc/cp/ChangeLog:

* constexpr.cc (maybe_warn_about_constant_value): Check DECL_NAME.

gcc/testsuite/ChangeLog:

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

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

Diff:
---
 gcc/cp/constexpr.cc   |  1 +
 gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C | 57 +++
 2 files changed, 58 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 41f862e7056e..20abbee3600e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -6434,6 +6434,7 @@ maybe_warn_about_constant_value (location_t loc, tree 
decl)
   && warn_interference_size
   && !OPTION_SET_P (param_destruct_interfere_size)
   && DECL_CONTEXT (decl) == std_node
+  && DECL_NAME (decl)
   && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size")
   && (LOCATION_FILE (input_location) != main_input_filename
  || module_exporting_p ())
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
new file mode 100644
index ..1cb65f10a1d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
@@ -0,0 +1,57 @@
+// PR c++/116676
+// { dg-do compile { target c++17 } }
+
+namespace std {
+typedef __SIZE_TYPE__ size_t;
+
+  template
+struct remove_reference
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&>
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&&>
+{ typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&
+move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+template  struct tuple_size;
+template  struct tuple_element;
+template  class __pair_base {};
+template 
+struct pair {
+  _T1 first;
+  _T2 second;
+  template 
+  explicit constexpr pair(const _T1 &__a, const _T2 &__b)
+  : first(__a), second(__b) {}
+};
+template 
+struct tuple_size>
+{
+static constexpr size_t value = 2;
+};
+template 
+struct tuple_element<0, pair<_Tp1, _Tp2>> {
+  typedef _Tp1 type;
+};
+template 
+struct tuple_element<1, pair<_Tp1, _Tp2>> {
+  typedef _Tp2 type;
+};
+
+template 
+constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type &
+get(pair<_Tp1, _Tp2> &&__in) noexcept {
+  return (std::move(__in).first);
+}
+int t;
+auto [a, b] = std::pair{t, 1};
+}
+


[gcc r13-9031] c++: crash with anon VAR_DECL [PR116676]

2024-09-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c8682dd76e31ee4bc4dede23c78d6d66de350e83

commit r13-9031-gc8682dd76e31ee4bc4dede23c78d6d66de350e83
Author: Marek Polacek 
Date:   Mon Sep 16 16:42:38 2024 -0400

c++: crash with anon VAR_DECL [PR116676]

r12-3495 added maybe_warn_about_constant_value which will crash if
it gets a nameless VAR_DECL, which is what happens in this PR.

We created this VAR_DECL in cp_parser_decomposition_declaration.

PR c++/116676

gcc/cp/ChangeLog:

* constexpr.cc (maybe_warn_about_constant_value): Check DECL_NAME.

gcc/testsuite/ChangeLog:

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

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

Diff:
---
 gcc/cp/constexpr.cc   |  1 +
 gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C | 57 +++
 2 files changed, 58 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 12dd9010148e..fb8a1023b222 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -6835,6 +6835,7 @@ maybe_warn_about_constant_value (location_t loc, tree 
decl)
   && warn_interference_size
   && !OPTION_SET_P (param_destruct_interfere_size)
   && DECL_CONTEXT (decl) == std_node
+  && DECL_NAME (decl)
   && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size")
   && (LOCATION_FILE (input_location) != main_input_filename
  || module_exporting_p ())
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
new file mode 100644
index ..1cb65f10a1d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
@@ -0,0 +1,57 @@
+// PR c++/116676
+// { dg-do compile { target c++17 } }
+
+namespace std {
+typedef __SIZE_TYPE__ size_t;
+
+  template
+struct remove_reference
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&>
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&&>
+{ typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&
+move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+template  struct tuple_size;
+template  struct tuple_element;
+template  class __pair_base {};
+template 
+struct pair {
+  _T1 first;
+  _T2 second;
+  template 
+  explicit constexpr pair(const _T1 &__a, const _T2 &__b)
+  : first(__a), second(__b) {}
+};
+template 
+struct tuple_size>
+{
+static constexpr size_t value = 2;
+};
+template 
+struct tuple_element<0, pair<_Tp1, _Tp2>> {
+  typedef _Tp1 type;
+};
+template 
+struct tuple_element<1, pair<_Tp1, _Tp2>> {
+  typedef _Tp2 type;
+};
+
+template 
+constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type &
+get(pair<_Tp1, _Tp2> &&__in) noexcept {
+  return (std::move(__in).first);
+}
+int t;
+auto [a, b] = std::pair{t, 1};
+}
+


[gcc r14-10675] c++: crash with anon VAR_DECL [PR116676]

2024-09-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:f1dc18250d82cd123fcf9aef0a95608e4ec63d58

commit r14-10675-gf1dc18250d82cd123fcf9aef0a95608e4ec63d58
Author: Marek Polacek 
Date:   Mon Sep 16 16:42:38 2024 -0400

c++: crash with anon VAR_DECL [PR116676]

r12-3495 added maybe_warn_about_constant_value which will crash if
it gets a nameless VAR_DECL, which is what happens in this PR.

We created this VAR_DECL in cp_parser_decomposition_declaration.

PR c++/116676

gcc/cp/ChangeLog:

* constexpr.cc (maybe_warn_about_constant_value): Check DECL_NAME.

gcc/testsuite/ChangeLog:

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

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

Diff:
---
 gcc/cp/constexpr.cc   |  1 +
 gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C | 57 +++
 2 files changed, 58 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 9b36f7628f36..853694d78a56 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7225,6 +7225,7 @@ maybe_warn_about_constant_value (location_t loc, tree 
decl)
   && warn_interference_size
   && !OPTION_SET_P (param_destruct_interfere_size)
   && DECL_CONTEXT (decl) == std_node
+  && DECL_NAME (decl)
   && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size")
   && (LOCATION_FILE (input_location) != main_input_filename
  || module_exporting_p ())
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
new file mode 100644
index ..1cb65f10a1d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
@@ -0,0 +1,57 @@
+// PR c++/116676
+// { dg-do compile { target c++17 } }
+
+namespace std {
+typedef __SIZE_TYPE__ size_t;
+
+  template
+struct remove_reference
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&>
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&&>
+{ typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&
+move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+template  struct tuple_size;
+template  struct tuple_element;
+template  class __pair_base {};
+template 
+struct pair {
+  _T1 first;
+  _T2 second;
+  template 
+  explicit constexpr pair(const _T1 &__a, const _T2 &__b)
+  : first(__a), second(__b) {}
+};
+template 
+struct tuple_size>
+{
+static constexpr size_t value = 2;
+};
+template 
+struct tuple_element<0, pair<_Tp1, _Tp2>> {
+  typedef _Tp1 type;
+};
+template 
+struct tuple_element<1, pair<_Tp1, _Tp2>> {
+  typedef _Tp2 type;
+};
+
+template 
+constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type &
+get(pair<_Tp1, _Tp2> &&__in) noexcept {
+  return (std::move(__in).first);
+}
+int t;
+auto [a, b] = std::pair{t, 1};
+}
+


[gcc r15-3672] c++: crash with anon VAR_DECL [PR116676]

2024-09-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:dfe0d4389a3ce43179563a63046ad3e74d615a08

commit r15-3672-gdfe0d4389a3ce43179563a63046ad3e74d615a08
Author: Marek Polacek 
Date:   Mon Sep 16 16:42:38 2024 -0400

c++: crash with anon VAR_DECL [PR116676]

r12-3495 added maybe_warn_about_constant_value which will crash if
it gets a nameless VAR_DECL, which is what happens in this PR.

We created this VAR_DECL in cp_parser_decomposition_declaration.

PR c++/116676

gcc/cp/ChangeLog:

* constexpr.cc (maybe_warn_about_constant_value): Check DECL_NAME.

gcc/testsuite/ChangeLog:

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

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constexpr.cc   |  1 +
 gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C | 57 +++
 2 files changed, 58 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index d0f617481413..c3668b0d7d3f 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7222,6 +7222,7 @@ maybe_warn_about_constant_value (location_t loc, tree 
decl)
   && warn_interference_size
   && !OPTION_SET_P (param_destruct_interfere_size)
   && DECL_CONTEXT (decl) == std_node
+  && DECL_NAME (decl)
   && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size")
   && (LOCATION_FILE (input_location) != main_input_filename
  || module_exporting_p ())
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
new file mode 100644
index ..1cb65f10a1d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-116676.C
@@ -0,0 +1,57 @@
+// PR c++/116676
+// { dg-do compile { target c++17 } }
+
+namespace std {
+typedef __SIZE_TYPE__ size_t;
+
+  template
+struct remove_reference
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&>
+{ typedef _Tp type; };
+
+  template
+struct remove_reference<_Tp&&>
+{ typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&
+move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+template  struct tuple_size;
+template  struct tuple_element;
+template  class __pair_base {};
+template 
+struct pair {
+  _T1 first;
+  _T2 second;
+  template 
+  explicit constexpr pair(const _T1 &__a, const _T2 &__b)
+  : first(__a), second(__b) {}
+};
+template 
+struct tuple_size>
+{
+static constexpr size_t value = 2;
+};
+template 
+struct tuple_element<0, pair<_Tp1, _Tp2>> {
+  typedef _Tp1 type;
+};
+template 
+struct tuple_element<1, pair<_Tp1, _Tp2>> {
+  typedef _Tp2 type;
+};
+
+template 
+constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type &
+get(pair<_Tp1, _Tp2> &&__in) noexcept {
+  return (std::move(__in).first);
+}
+int t;
+auto [a, b] = std::pair{t, 1};
+}
+


[gcc r14-10668] c++: ICE with TTP [PR96097]

2024-09-12 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:4088319e7ce98f813988a36f98a18ee30ff7f1d8

commit r14-10668-g4088319e7ce98f813988a36f98a18ee30ff7f1d8
Author: Marek Polacek 
Date:   Tue Sep 3 17:01:48 2024 -0400

c++: ICE with TTP [PR96097]

We crash when dependent_type_p gets a TEMPLATE_TYPE_PARM outside
a template.  That happens here because in

  template  typename X>
  void func() {}
  template 
  struct Y {};
  void g() { func(); }

when performing overload resolution for func() we have to check
if U matches T and I matches TT.  So we wind up in
coerce_template_template_parm/PARM_DECL.  TREE_TYPE (arg) is int
so we try to substitute TT's type, which is T::type.  But we have
nothing to substitute T with.  And we call make_typename_type where
ctx is still T, which checks dependent_scope_p and we trip the assert.

It should work to always perform the substitution in a template context.
If the result still contains template parameters, we cannot say if they
match.

PR c++/96097

gcc/cp/ChangeLog:

* pt.cc (coerce_template_template_parm): Increment
processing_template_decl before calling tsubst.

gcc/testsuite/ChangeLog:

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

(cherry picked from commit 25ac2bb57ae400621050a7e0845994336ca83b99)

Diff:
---
 gcc/cp/pt.cc  |  2 ++
 gcc/testsuite/g++.dg/template/ttp44.C | 13 +
 2 files changed, 15 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6695e4ff49f0..85228b9f9435 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7933,7 +7933,9 @@ coerce_template_template_parm (tree parm,
 i.e. the parameter list of TT depends on earlier parameters.  */
   if (!uses_template_parms (TREE_TYPE (arg)))
{
+ ++processing_template_decl;
  tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl);
+ --processing_template_decl;
  if (!uses_template_parms (t)
  && !same_type_p (t, TREE_TYPE (arg)))
return 0;
diff --git a/gcc/testsuite/g++.dg/template/ttp44.C 
b/gcc/testsuite/g++.dg/template/ttp44.C
new file mode 100644
index ..2a4129752433
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp44.C
@@ -0,0 +1,13 @@
+// PR c++/96097
+// { dg-do compile }
+
+template  class X>
+void func() {}
+
+template 
+struct Y {};
+
+void test()
+{
+  func();
+}


[gcc r15-3603] c++: ICE with TTP [PR96097]

2024-09-12 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:25ac2bb57ae400621050a7e0845994336ca83b99

commit r15-3603-g25ac2bb57ae400621050a7e0845994336ca83b99
Author: Marek Polacek 
Date:   Tue Sep 3 17:01:48 2024 -0400

c++: ICE with TTP [PR96097]

We crash when dependent_type_p gets a TEMPLATE_TYPE_PARM outside
a template.  That happens here because in

  template  typename X>
  void func() {}
  template 
  struct Y {};
  void g() { func(); }

when performing overload resolution for func() we have to check
if U matches T and I matches TT.  So we wind up in
coerce_template_template_parm/PARM_DECL.  TREE_TYPE (arg) is int
so we try to substitute TT's type, which is T::type.  But we have
nothing to substitute T with.  And we call make_typename_type where
ctx is still T, which checks dependent_scope_p and we trip the assert.

It should work to always perform the substitution in a template context.
If the result still contains template parameters, we cannot say if they
match.

PR c++/96097

gcc/cp/ChangeLog:

* pt.cc (coerce_template_template_parm): Increment
processing_template_decl before calling tsubst.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/pt.cc  |  2 ++
 gcc/testsuite/g++.dg/template/ttp44.C | 13 +
 2 files changed, 15 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index cb3164d49147..769e7999dac1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7951,7 +7951,9 @@ coerce_template_template_parm (tree parm, tree arg, 
tsubst_flags_t complain,
 i.e. the parameter list of TT depends on earlier parameters.  */
   if (!uses_template_parms (TREE_TYPE (arg)))
{
+ ++processing_template_decl;
  tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl);
+ --processing_template_decl;
  if (!uses_template_parms (t)
  && !same_type_p (t, TREE_TYPE (arg)))
return false;
diff --git a/gcc/testsuite/g++.dg/template/ttp44.C 
b/gcc/testsuite/g++.dg/template/ttp44.C
new file mode 100644
index ..2a4129752433
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp44.C
@@ -0,0 +1,13 @@
+// PR c++/96097
+// { dg-do compile }
+
+template  class X>
+void func() {}
+
+template 
+struct Y {};
+
+void test()
+{
+  func();
+}


[gcc r15-3572] c++: mutable temps in rodata [PR116369]

2024-09-10 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:2801a49d1144bce5568b527d1972952ad3420f66

commit r15-3572-g2801a49d1144bce5568b527d1972952ad3420f66
Author: Marek Polacek 
Date:   Thu Aug 29 15:13:03 2024 -0400

c++: mutable temps in rodata [PR116369]

Here we wrongly mark the reference temporary for g TREE_READONLY,
so it's put in .rodata and so we can't modify its subobject even
when the subobject is marked mutable.  This is so since r9-869.
r14-1785 fixed a similar problem, but not in set_up_extended_ref_temp.

PR c++/116369

gcc/cp/ChangeLog:

* call.cc (set_up_extended_ref_temp): Don't mark a temporary
TREE_READONLY if its type is TYPE_HAS_MUTABLE_P.

gcc/testsuite/ChangeLog:

* g++.dg/tree-ssa/initlist-opt7.C: New test.

Diff:
---
 gcc/cp/call.cc|  4 +++-
 gcc/testsuite/g++.dg/tree-ssa/initlist-opt7.C | 13 +
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index fa7f05d76f68..d30f36d49ff6 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13964,7 +13964,9 @@ set_up_extended_ref_temp (tree decl, tree expr, 
vec **cleanups,
   init = cp_fully_fold (init);
   if (TREE_CONSTANT (init))
 {
-  if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type))
+  if (literal_type_p (type)
+ && CP_TYPE_CONST_NON_VOLATILE_P (type)
+ && !TYPE_HAS_MUTABLE_P (type))
{
  /* 5.19 says that a constant expression can include an
 lvalue-rvalue conversion applied to "a glvalue of literal type
diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt7.C 
b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt7.C
new file mode 100644
index ..2420db502a67
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt7.C
@@ -0,0 +1,13 @@
+// PR c++/116369
+// { dg-do run { target c++11 } }
+
+struct f{
+  mutable int t;
+};
+
+const f &g = {1};
+
+int main()
+{
+  g.t++;
+}


[gcc r14-10648] c++: vtable referring to "unavailable" virtual fn [PR116606]

2024-09-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:fe668633f6b5819ba04d80f13343ee7f5bba1c5b

commit r14-10648-gfe668633f6b5819ba04d80f13343ee7f5bba1c5b
Author: Marek Polacek 
Date:   Thu Sep 5 13:01:59 2024 -0400

c++: vtable referring to "unavailable" virtual fn [PR116606]

mark_vtable_entries already has

   /* It's OK for the vtable to refer to deprecated virtual functions.  */
   warning_sentinel w(warn_deprecated_decl);

but that doesn't cover __attribute__((unavailable)).  We can use the
following override to cover both.

PR c++/116606

gcc/cp/ChangeLog:

* decl2.cc (mark_vtable_entries): Temporarily override 
deprecated_state to
UNAVAILABLE_DEPRECATED_SUPPRESS.  Remove a warning_sentinel.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-unavailable-13.C: New test.

(cherry picked from commit d9d34f9a91371dea4bab0b54b2d7f762a6cc23e0)

Diff:
---
 gcc/cp/decl2.cc| 3 ++-
 gcc/testsuite/g++.dg/ext/attr-unavailable-13.C | 8 
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index af2e08c8a63..f6c760338cc 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2172,7 +2172,8 @@ static void
 mark_vtable_entries (tree decl, vec &consteval_vtables)
 {
   /* It's OK for the vtable to refer to deprecated virtual functions.  */
-  warning_sentinel w(warn_deprecated_decl);
+  auto du = make_temp_override (deprecated_state,
+   UNAVAILABLE_DEPRECATED_SUPPRESS);
 
   bool consteval_seen = false;
 
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-13.C 
b/gcc/testsuite/g++.dg/ext/attr-unavailable-13.C
new file mode 100644
index 000..9ca40005419
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-13.C
@@ -0,0 +1,8 @@
+// PR c++/116606
+// { dg-do compile }
+
+struct C {
+__attribute__((unavailable)) virtual void f() {}
+};
+
+C c;


[gcc r15-3493] c++: vtable referring to "unavailable" virtual fn [PR116606]

2024-09-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d9d34f9a91371dea4bab0b54b2d7f762a6cc23e0

commit r15-3493-gd9d34f9a91371dea4bab0b54b2d7f762a6cc23e0
Author: Marek Polacek 
Date:   Thu Sep 5 13:01:59 2024 -0400

c++: vtable referring to "unavailable" virtual fn [PR116606]

mark_vtable_entries already has

   /* It's OK for the vtable to refer to deprecated virtual functions.  */
   warning_sentinel w(warn_deprecated_decl);

but that doesn't cover __attribute__((unavailable)).  We can use the
following override to cover both.

PR c++/116606

gcc/cp/ChangeLog:

* decl2.cc (mark_vtable_entries): Temporarily override 
deprecated_state to
UNAVAILABLE_DEPRECATED_SUPPRESS.  Remove a warning_sentinel.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-unavailable-13.C: New test.

Diff:
---
 gcc/cp/decl2.cc| 3 ++-
 gcc/testsuite/g++.dg/ext/attr-unavailable-13.C | 8 
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 3c4f34868ee..0279372488c 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2180,7 +2180,8 @@ static void
 mark_vtable_entries (tree decl, vec &consteval_vtables)
 {
   /* It's OK for the vtable to refer to deprecated virtual functions.  */
-  warning_sentinel w(warn_deprecated_decl);
+  auto du = make_temp_override (deprecated_state,
+   UNAVAILABLE_DEPRECATED_SUPPRESS);
 
   bool consteval_seen = false;
 
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-13.C 
b/gcc/testsuite/g++.dg/ext/attr-unavailable-13.C
new file mode 100644
index 000..9ca40005419
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-13.C
@@ -0,0 +1,8 @@
+// PR c++/116606
+// { dg-do compile }
+
+struct C {
+__attribute__((unavailable)) virtual void f() {}
+};
+
+C c;


[gcc r15-3490] doc: remove stray character

2024-09-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c880fca6cdb16c5efe3a12ee7ecdb2435f5e7105

commit r15-3490-gc880fca6cdb16c5efe3a12ee7ecdb2435f5e7105
Author: Marek Polacek 
Date:   Thu Sep 5 13:17:06 2024 -0400

doc: remove stray character

There's an extra '+'.

gcc/ChangeLog:

* doc/invoke.texi: Remove an extra char in @item sme2.

Diff:
---
 gcc/doc/invoke.texi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 193db761d64..0f9b1bab19f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -21847,7 +21847,7 @@ Enable the Scalable Matrix Extension.
 Enable the FEAT_SME_I16I64 extension to SME.
 @item sme-f64f64
 Enable the FEAT_SME_F64F64 extension to SME.
-+@item sme2
+@item sme2
 Enable the Scalable Matrix Extension 2.  This also enables SME instructions.
 @item lse128
 Enable the LSE128 128-bit atomic instructions extension.  This also


[gcc r15-3489] c++: fn redecl in fn scope wrongly accepted [PR116239]

2024-09-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d44cae2d9310660e3e47f15202e86e4f73f15b37

commit r15-3489-gd44cae2d9310660e3e47f15202e86e4f73f15b37
Author: Marek Polacek 
Date:   Fri Aug 30 14:12:22 2024 -0400

c++: fn redecl in fn scope wrongly accepted [PR116239]

Redeclaration such as

  void f(void);
  consteval void f(void);

is invalid.  In a namespace scope, we detect the collision in
validate_constexpr_redeclaration, but not when one declaration is
at block scope.

When we have

  void f(void);
  void g() { consteval void f(void); }

we call pushdecl on the second f and call push_local_extern_decl_alias.
It finds the namespace-scope f:

for (ovl_iterator iter (binding); iter; ++iter)
  if (decls_match (decl, *iter, /*record_versions*/false))
{
  alias = *iter;
  break;
}

but decls_match says they match so we just set DECL_LOCAL_DECL_ALIAS
(and do not call another pushdecl leading to duplicate_decls which
would detect mismatching return types, for example).  I don't think
we want to change decls_match, so a simple fix is to detect the
problem in push_local_extern_decl_alias.

PR c++/116239

gcc/cp/ChangeLog:

* cp-tree.h (validate_constexpr_redeclaration): Declare.
* decl.cc (validate_constexpr_redeclaration): No longer static.
* name-lookup.cc (push_local_extern_decl_alias): Call
validate_constexpr_redeclaration.

gcc/testsuite/ChangeLog:

* g++.dg/diagnostic/redeclaration-6.C: New test.

Diff:
---
 gcc/cp/cp-tree.h  |  1 +
 gcc/cp/decl.cc|  2 +-
 gcc/cp/name-lookup.cc |  2 ++
 gcc/testsuite/g++.dg/diagnostic/redeclaration-6.C | 34 +++
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2eeb5e3e8b1..1a763b683de 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6992,6 +6992,7 @@ extern bool member_like_constrained_friend_p  (tree);
 extern bool fns_correspond (tree, tree);
 extern int decls_match (tree, tree, bool = true);
 extern bool maybe_version_functions(tree, tree, bool);
+extern bool validate_constexpr_redeclaration   (tree, tree);
 extern bool merge_default_template_args(tree, tree, bool);
 extern tree duplicate_decls(tree, tree,
 bool hiding = false,
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 7bad3047ad9..f4128dbccdf 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1412,7 +1412,7 @@ check_redeclaration_exception_specification (tree 
new_decl,
 /* Return true if OLD_DECL and NEW_DECL agree on constexprness.
Otherwise issue diagnostics.  */
 
-static bool
+bool
 validate_constexpr_redeclaration (tree old_decl, tree new_decl)
 {
   old_decl = STRIP_TEMPLATE (old_decl);
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 7a6cc244c15..cd3947cbe4f 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3637,6 +3637,8 @@ push_local_extern_decl_alias (tree decl)
  if (decls_match (decl, *iter, /*record_versions*/false))
{
  alias = *iter;
+ if (!validate_constexpr_redeclaration (alias, decl))
+   return;
  break;
}
 
diff --git a/gcc/testsuite/g++.dg/diagnostic/redeclaration-6.C 
b/gcc/testsuite/g++.dg/diagnostic/redeclaration-6.C
new file mode 100644
index 000..ed8d4af7792
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/redeclaration-6.C
@@ -0,0 +1,34 @@
+// PR c++/116239
+// { dg-do compile { target c++20 } }
+
+consteval void f1();
+void f2();
+constexpr void f3();
+void f4();
+consteval void f5();
+constexpr void f6();
+
+void
+g ()
+{
+  void f1();   // { dg-error "differs in .consteval." }
+  consteval void f2(); // { dg-error "differs in .consteval." }
+
+  void f3();   // { dg-error "differs in .constexpr." }
+  constexpr void f4();  // { dg-error "differs in .constexpr." }
+
+  consteval void f5();
+  constexpr void f6();
+
+  void f7();
+  consteval void f7(); // { dg-error "differs in .consteval." }
+
+  consteval void f8();
+  void f8();   // { dg-error "differs in .consteval." }
+
+  void f9();
+  constexpr void f9(); // { dg-error "differs in .constexpr." }
+
+  constexpr void f10();
+  void f10();  // { dg-error "differs in .constexpr." }
+}


[gcc r15-3456] c++: cleanup coerce_template_template_parm

2024-09-04 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:dedf453477aa966493541a484b2d4ee5a17e5b61

commit r15-3456-gdedf453477aa966493541a484b2d4ee5a17e5b61
Author: Marek Polacek 
Date:   Wed Sep 4 13:43:52 2024 -0400

c++: cleanup coerce_template_template_parm

This function could use some sprucing up.

gcc/cp/ChangeLog:

* pt.cc (coerce_template_template_parm): Return bool instead of int.

Diff:
---
 gcc/cp/pt.cc | 35 ---
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 747e627f547..1225c668e87 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7887,25 +7887,22 @@ convert_nontype_argument (tree type, tree expr, 
tsubst_flags_t complain)
   return convert_from_reference (expr);
 }
 
-/* Subroutine of coerce_template_template_parms, which returns 1 if
-   PARM_PARM and ARG_PARM match using the rule for the template
-   parameters of template template parameters. Both PARM and ARG are
-   template parameters; the rest of the arguments are the same as for
-   coerce_template_template_parms.
- */
-static int
-coerce_template_template_parm (tree parm,
-  tree arg,
-  tsubst_flags_t complain,
-  tree in_decl,
-  tree outer_args)
+/* Subroutine of coerce_template_template_parms, which returns true if
+   PARM and ARG match using the rule for the template parameters of
+   template template parameters.  Both PARM and ARG are template parameters;
+   the rest of the arguments are the same as for
+   coerce_template_template_parms.  */
+
+static bool
+coerce_template_template_parm (tree parm, tree arg, tsubst_flags_t complain,
+  tree in_decl, tree outer_args)
 {
   if (arg == NULL_TREE || error_operand_p (arg)
   || parm == NULL_TREE || error_operand_p (parm))
-return 0;
+return false;
 
   if (TREE_CODE (arg) != TREE_CODE (parm))
-return 0;
+return false;
 
   switch (TREE_CODE (parm))
 {
@@ -7916,7 +7913,7 @@ coerce_template_template_parm (tree parm,
   {
if (!coerce_template_template_parms
(parm, arg, complain, in_decl, outer_args))
- return 0;
+ return false;
   }
   /* Fall through.  */
 
@@ -7924,7 +7921,7 @@ coerce_template_template_parm (tree parm,
   if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg))
  && !TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm)))
/* Argument is a parameter pack but parameter is not.  */
-   return 0;
+   return false;
   break;
 
 case PARM_DECL:
@@ -7940,13 +7937,13 @@ coerce_template_template_parm (tree parm,
  tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl);
  if (!uses_template_parms (t)
  && !same_type_p (t, TREE_TYPE (arg)))
-   return 0;
+   return false;
}
 
   if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg))
  && !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
/* Argument is a parameter pack but parameter is not.  */
-   return 0;
+   return false;
 
   break;
 
@@ -7954,7 +7951,7 @@ coerce_template_template_parm (tree parm,
   gcc_unreachable ();
 }
 
-  return 1;
+  return true;
 }
 
 /* Coerce template argument list ARGLIST for use with template


[gcc r15-3455] c++: noexcept and pointer to member function type [PR113108]

2024-09-04 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c755c7a32590e2eef5a8b062b9756c1513910246

commit r15-3455-gc755c7a32590e2eef5a8b062b9756c1513910246
Author: Marek Polacek 
Date:   Tue Sep 3 13:04:09 2024 -0400

c++: noexcept and pointer to member function type [PR113108]

We ICE in nothrow_spec_p because it got a DEFERRED_NOEXCEPT.
This DEFERRED_NOEXCEPT was created in implicitly_declare_fn
when declaring

  Foo& operator=(Foo&&) = default;

in the test.  The problem is that in resolve_overloaded_unification
we call maybe_instantiate_noexcept before try_one_overload only in
the TEMPLATE_ID_EXPR case.

PR c++/113108

gcc/cp/ChangeLog:

* pt.cc (resolve_overloaded_unification): Call
maybe_instantiate_noexcept.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/noexcept-type28.C: New test.

Diff:
---
 gcc/cp/pt.cc |  2 ++
 gcc/testsuite/g++.dg/cpp1z/noexcept-type28.C | 18 ++
 2 files changed, 20 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 024fa8a5529..747e627f547 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23787,6 +23787,8 @@ resolve_overloaded_unification (tree tparms,
 for (lkp_iterator iter (arg); iter; ++iter)
   {
tree fn = *iter;
+   if (flag_noexcept_type)
+ maybe_instantiate_noexcept (fn, tf_none);
if (try_one_overload (tparms, targs, tempargs, parm, TREE_TYPE (fn),
  strict, sub_strict, addr_p, explain_p)
&& (!goodfn || !decls_match (goodfn, fn)))
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type28.C 
b/gcc/testsuite/g++.dg/cpp1z/noexcept-type28.C
new file mode 100644
index 000..bf0b927b8ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type28.C
@@ -0,0 +1,18 @@
+// PR c++/113108
+// { dg-do compile { target c++17 } }
+
+template 
+struct Foo {
+Foo& operator=(Foo&&) = default;
+T data;
+};
+
+template 
+void consume(Foo& (Foo::*)(Foo&&) ) {}
+
+template 
+void consume(Foo& (Foo::*)(Foo&&) noexcept) {}
+
+int main() {
+consume(&Foo::operator=);
+}


[gcc r15-3428] c++: add fixed test [PR109095]

2024-09-03 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:5f3a6e26aab16a792176b33fbee1456a91aaebf2

commit r15-3428-g5f3a6e26aab16a792176b33fbee1456a91aaebf2
Author: Marek Polacek 
Date:   Tue Sep 3 13:32:35 2024 -0400

c++: add fixed test [PR109095]

Fixed by r13-6693.

PR c++/109095

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class66.C: New test.

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

diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class66.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-class66.C
new file mode 100644
index ..385b290521fe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class66.C
@@ -0,0 +1,19 @@
+// PR c++/109095
+// { dg-do compile { target c++20 } }
+
+template< typename T >
+struct bar
+{};
+
+template< int X >
+struct baz
+{};
+
+template< auto N, template< auto N2 > typename TT >
+struct foo;
+
+template< typename T, bar< T > B, template< T N2 > typename TT >
+struct foo< B, TT >
+{};
+
+foo< bar< int >{}, baz > x;


[gcc r15-3326] c++: add fixed test [PR101099]

2024-08-30 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:b1765a5737f011bfd992c6ab78018d6e9042f074

commit r15-3326-gb1765a5737f011bfd992c6ab78018d6e9042f074
Author: Marek Polacek 
Date:   Fri Aug 30 17:09:19 2024 -0400

c++: add fixed test [PR101099]

-fconcepts-ts is no longer supported so this can't be made to ICE
anymore.

PR c++/101099

gcc/testsuite/ChangeLog:

* g++.dg/concepts/pr101099.C: New test.

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

diff --git a/gcc/testsuite/g++.dg/concepts/pr101099.C 
b/gcc/testsuite/g++.dg/concepts/pr101099.C
new file mode 100644
index ..82fd87c843be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/pr101099.C
@@ -0,0 +1,6 @@
+// PR c++/101099
+// { dg-do compile { target c++11 } }
+// { dg-options "-fconcepts" }
+
+#include 
+constexpr auto list = { 1, 2, 3 };


[gcc r15-3325] c++: add fixed test [PR115616]

2024-08-30 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:ffd56dcc11e32033a1f3a964af584dc32321a125

commit r15-3325-gffd56dcc11e32033a1f3a964af584dc32321a125
Author: Marek Polacek 
Date:   Fri Aug 30 16:34:11 2024 -0400

c++: add fixed test [PR115616]

This got fixed by r15-2120.

PR c++/115616

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/testsuite/g++.dg/template/friend83.C | 24 
 1 file changed, 24 insertions(+)

diff --git a/gcc/testsuite/g++.dg/template/friend83.C 
b/gcc/testsuite/g++.dg/template/friend83.C
new file mode 100644
index ..edd29614b315
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend83.C
@@ -0,0 +1,24 @@
+// PR c++/115616
+// { dg-do compile { target c++20 } }
+
+template  void bar() {}
+
+template 
+struct Reader
+{
+template 
+friend void foo(Reader);
+};
+
+template 
+struct Writer
+{
+template 
+friend void foo(Reader) {bar();}
+};
+
+int main()
+{
+foo<10>(Reader{});
+Writer{};
+}


[gcc r15-3274] c++: wrong error due to std::initializer_list opt [PR116476]

2024-08-28 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:9f79c7ddff5f1b004803931406ad17eaba095fff

commit r15-3274-g9f79c7ddff5f1b004803931406ad17eaba095fff
Author: Marek Polacek 
Date:   Wed Aug 28 15:45:49 2024 -0400

c++: wrong error due to std::initializer_list opt [PR116476]

Here maybe_init_list_as_array gets elttype=field, init={NON_LVALUE_EXPR <2>}
and it tries to convert the init's element type (int) to field
using implicit_conversion, which works, so overall maybe_init_list_as_array
is successful.

But it constifies init_elttype so we end up with "const int".  Later,
when we actually perform the conversion and invoke field::field(T&&),
we end up with this error:

  error: binding reference of type 'int&&' to 'const int' discards 
qualifiers

So I think maybe_init_list_as_array should try to perform the conversion,
like it does below with fc.

PR c++/116476

gcc/cp/ChangeLog:

* call.cc (maybe_init_list_as_array): Try convert_like and see if it
worked.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/initlist-opt2.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/call.cc |  6 +-
 gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C | 21 +
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 623e4c66c117..fa7f05d76f68 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -4319,6 +4319,7 @@ maybe_init_list_as_array (tree elttype, tree init)
   /* Check with a stub expression to weed out special cases, and check whether
  we call the same function for direct-init as copy-list-init.  */
   conversion_obstack_sentinel cos;
+  init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST);
   tree arg = build_stub_object (init_elttype);
   conversion *c = implicit_conversion (elttype, init_elttype, arg, false,
   LOOKUP_NORMAL, tf_none);
@@ -4326,6 +4327,10 @@ maybe_init_list_as_array (tree elttype, tree init)
 c = next_conversion (c);
   if (!c || c->kind != ck_user)
 return NULL_TREE;
+  /* Check that we actually can perform the conversion.  */
+  if (convert_like (c, arg, tf_none) == error_mark_node)
+/* Let the normal code give the error.  */
+return NULL_TREE;
 
   tree first = CONSTRUCTOR_ELT (init, 0)->value;
   conversion *fc = implicit_conversion (elttype, init_elttype, first, false,
@@ -4358,7 +4363,6 @@ maybe_init_list_as_array (tree elttype, tree init)
   if (!is_xible (INIT_EXPR, elttype, copy_argtypes))
 return NULL_TREE;
 
-  init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST);
   tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init));
   arr = finish_compound_literal (arr, init, tf_none);
   DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C
new file mode 100644
index ..6c71857daabc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C
@@ -0,0 +1,21 @@
+// PR c++/116476
+// { dg-do compile { target c++11 } }
+
+namespace std {
+template 
+class initializer_list {
+  T *_M_len;
+  __SIZE_TYPE__ size;
+};
+} // namespace std
+
+
+template 
+struct field {
+field(T &&) {}
+};
+struct vector {
+  vector(std::initializer_list>) { }
+};
+
+vector fields_normal{2};


[gcc r15-3262] c++: ICE with ()-init and TARGET_EXPR eliding [PR116424]

2024-08-28 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:15f857af2943a4aa282d04ff71f860352ad3291b

commit r15-3262-g15f857af2943a4aa282d04ff71f860352ad3291b
Author: Marek Polacek 
Date:   Tue Aug 27 18:25:17 2024 -0400

c++: ICE with ()-init and TARGET_EXPR eliding [PR116424]

Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:

  gcc_checking_assert (!TARGET_EXPR_ELIDING_P (*expr_p)
   || !TREE_ADDRESSABLE (TREE_TYPE (*expr_p)));

We cannot elide the TARGET_EXPR because we're taking its address.

It is set as eliding in massage_init_elt.  I've tried to not set
TARGET_EXPR_ELIDING_P when the context is not direct-initialization.
That didn't work: even when it's not direct-initialization now, it
can become one later, for instance, after split_nonconstant_init.
One problem is that replace_placeholders_for_class_temp_r will replace
placeholders in non-eliding TARGET_EXPRs with the slot, but if we then
elide the TARGET_EXPR, we end up with a "stray" VAR_DECL and crash.
(Only some TARGET_EXPRs are handled by replace_decl.)

I thought I'd have to go back to
 but
then I realized that this problem occurrs only with ()-init but not
{}-init.  With {}-init, there is no problem, because we are clearing
TARGET_EXPR_ELIDING_P in process_init_constructor_record:

   /* We can't actually elide the temporary when initializing a
  potentially-overlapping field from a function that returns by
  value.  */
   if (ce->index
   && TREE_CODE (next) == TARGET_EXPR
   && unsafe_copy_elision_p (ce->index, next))
 TARGET_EXPR_ELIDING_P (next) = false;

But that does not happen for ()-init because we have no ce->index.
()-init doesn't allow brace elision so we don't really reshape them.

But I can just move the clearing a few lines down and then it handles
both ()-init and {}-init.

PR c++/116424

gcc/cp/ChangeLog:

* typeck2.cc (process_init_constructor_record): Move the clearing of
TARGET_EXPR_ELIDING_P down.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/paren-init38.C: New test.

Diff:
---
 gcc/cp/typeck2.cc | 14 +++---
 gcc/testsuite/g++.dg/cpp2a/paren-init38.C | 20 
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 30a6fbe95c99..a0c8f833ac1a 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1774,13 +1774,6 @@ process_init_constructor_record (tree type, tree init, 
int nested, int flags,
{
  gcc_assert (ce->value);
  next = massage_init_elt (fldtype, next, nested, flags, complain);
- /* We can't actually elide the temporary when initializing a
-potentially-overlapping field from a function that returns by
-value.  */
- if (ce->index
- && TREE_CODE (next) == TARGET_EXPR
- && unsafe_copy_elision_p (ce->index, next))
-   TARGET_EXPR_ELIDING_P (next) = false;
  ++idx;
}
}
@@ -1873,6 +1866,13 @@ process_init_constructor_record (tree type, tree init, 
int nested, int flags,
}
}
 
+  /* We can't actually elide the temporary when initializing a
+potentially-overlapping field from a function that returns by
+value.  */
+  if (TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (field, next))
+   TARGET_EXPR_ELIDING_P (next) = false;
+
   if (is_empty_field (field)
  && !TREE_SIDE_EFFECTS (next))
/* Don't add trivial initialization of an empty base/field to the
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init38.C 
b/gcc/testsuite/g++.dg/cpp2a/paren-init38.C
new file mode 100644
index ..58743e051da1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init38.C
@@ -0,0 +1,20 @@
+// PR c++/116424
+// { dg-do compile { target c++20 } }
+
+struct dd {
+  char *ptr;
+  dd();
+  dd(dd &&__str);
+};
+struct v {
+  dd n{};
+  int f = -1;
+  v operator|(const v &other) const;
+};
+struct cc : v {};
+static const cc a;
+static const cc b;
+static const cc c1(a | b);
+static const cc c2{a | b};
+static const cc c3 = cc(a | b);
+static const cc c4 = cc{a | b};


[gcc r14-10603] c++: fix ICE in convert_nontype_argument [PR116384]

2024-08-19 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:52da8588fd06198edcda81d7acf83ec92ccb63ef

commit r14-10603-g52da8588fd06198edcda81d7acf83ec92ccb63ef
Author: Marek Polacek 
Date:   Thu Aug 15 11:53:10 2024 -0400

c++: fix ICE in convert_nontype_argument [PR116384]

Here we ICE since r14-8291 in C++11/C++14 modes.  Fortunately
this is an easy one.

The important bit of r14-8291 is this:

@@ -20056,9 +20071,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
RETURN (retval);
  }
if (IMPLICIT_CONV_EXPR_NONTYPE_ARG (t))
- /* We'll pass this to convert_nontype_argument again, we don't need
-to actually perform any conversion here.  */
- RETURN (expr);
+ {
+   tree r = convert_nontype_argument (type, expr, complain);
+   if (r == NULL_TREE)
+ r = error_mark_node;
+   RETURN (r);
+ }

which obviously means that instead of returning right away we go
to convert_nontype_argument.  When type is error_mark_node and we're
in C++17, in convert_nontype_argument we go down this path:

  else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
   || cxx_dialect >= cxx17)
{
  expr = build_converted_constant_expr (type, expr, complain);
  if (expr == error_mark_node)
return (complain & tf_error) ? NULL_TREE : error_mark_node;
  // ...
}

but pre-C++17, we take a different route and end up crashing on
gcc_unreachable.

It would of course also work to check for error_mark_node early in
build_converted_constant_expr.

PR c++/116384

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Bail if tsubst
returns error_mark_node.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/vt-116384.C: New test.

(cherry picked from commit 8191f15022b0ea44fcb549449b0458d07ae02e0a)

Diff:
---
 gcc/cp/pt.cc   |  2 ++
 gcc/testsuite/g++.dg/cpp0x/vt-116384.C | 26 ++
 2 files changed, 28 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 96a4f45909d..8e6a7d1a64a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20220,6 +20220,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 case IMPLICIT_CONV_EXPR:
   {
tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+   if (type == error_mark_node)
+ RETURN (error_mark_node);
tree expr = RECUR (TREE_OPERAND (t, 0));
if (dependent_type_p (type) || type_dependent_expression_p (expr))
  {
diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-116384.C 
b/gcc/testsuite/g++.dg/cpp0x/vt-116384.C
new file mode 100644
index 000..54d7f0774c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/vt-116384.C
@@ -0,0 +1,26 @@
+// PR c++/116384
+// { dg-do compile { target c++11 } }
+
+namespace a {
+template  struct c;
+template  struct d;
+}
+namespace e {
+namespace g {
+template  using h = void;
+template  class, typename...> struct detector {};
+template  class i, typename... args>
+struct detector>, i, args...>;
+}
+template  class i, typename... args>
+using j = g::detector;
+template  using l = typename a::c::m;
+template  struct conjunction;
+namespace g {
+template  using n = l>::p>;
+}
+template  = true> class o;
+}
+struct r;
+template  using q = e::o;
+void s() { e::j f; }


[gcc r15-3027] c++: ICE with enum and conversion fn in template [PR115657]

2024-08-19 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:53283c3231a7b94e728619cccbf21170fb36b2a8

commit r15-3027-g53283c3231a7b94e728619cccbf21170fb36b2a8
Author: Marek Polacek 
Date:   Thu Aug 15 18:47:29 2024 -0400

c++: ICE with enum and conversion fn in template [PR115657]

Here we initialize an enumerator with a class prvalue with a conversion
function.  When we fold it in build_enumerator, we create a TARGET_EXPR
for the object, and subsequently crash in tsubst_expr, which should not
see such a code.

Normally, we fix similar problems by using an IMPLICIT_CONV_EXPR but here
I may get away with not using the result of fold_non_dependent_expr unless
the result is a constant.  A TARGET_EXPR is not constant.

PR c++/115657

gcc/cp/ChangeLog:

* decl.cc (build_enumerator): Call maybe_fold_non_dependent_expr
instead of fold_non_dependent_expr.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/constexpr-recursion2.C: New test.
* g++.dg/template/conv21.C: New test.

Diff:
---
 gcc/cp/decl.cc| 10 --
 gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C | 22 ++
 gcc/testsuite/g++.dg/template/conv21.C| 14 ++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index f23b635aec9..12139e1d862 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -17387,9 +17387,15 @@ build_enumerator (tree name, tree value, tree 
enumtype, tree attributes,
   tree type;
 
   /* scalar_constant_value will pull out this expression, so make sure
- it's folded as appropriate.  */
+ it's folded as appropriate.
+
+ Creating a TARGET_EXPR in a template breaks when substituting, and
+ here we would create it for instance when using a class prvalue with
+ a user-defined conversion function.  So don't use such a tree.  We
+ instantiate VALUE here to get errors about bad enumerators even in
+ a template that does not get instantiated.  */
   if (processing_template_decl)
-value = fold_non_dependent_expr (value);
+value = maybe_fold_non_dependent_expr (value);
 
   /* If the VALUE was erroneous, pretend it wasn't there; that will
  result in the enum being assigned the next value in sequence.  */
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C 
b/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C
new file mode 100644
index 000..f268f52e2b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C
@@ -0,0 +1,22 @@
+// PR c++/115657
+// { dg-do compile { target c++14 } }
+// { dg-options "-Wall" }
+
+// Like constexpr-recursion1.C but use a class with a conversion function.
+
+struct X {
+  constexpr operator int() { return 0; }
+};
+
+template 
+constexpr X f1 ()
+{
+  enum E { a = f1<0> () }; // { dg-error "called in a constant expression 
before its definition is complete|is not an integer constant" }
+  return {};
+}
+
+constexpr X f3 ()
+{
+  enum E { a = f3 () };// { dg-error "called in a constant expression 
before its definition is complete|is not an integer constant" }
+  return {};
+}
diff --git a/gcc/testsuite/g++.dg/template/conv21.C 
b/gcc/testsuite/g++.dg/template/conv21.C
new file mode 100644
index 000..1dc7b3d50d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv21.C
@@ -0,0 +1,14 @@
+// PR c++/115657
+// { dg-do compile { target c++11 } }
+
+struct NonIntegral
+{
+constexpr operator int() { return 0; }
+};
+
+template struct TemplatedStructural
+{
+enum { e = NonIntegral{} };
+};
+
+template struct TemplatedStructural;


[gcc r15-3026] c++: fix ICE in convert_nontype_argument [PR116384]

2024-08-19 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:8191f15022b0ea44fcb549449b0458d07ae02e0a

commit r15-3026-g8191f15022b0ea44fcb549449b0458d07ae02e0a
Author: Marek Polacek 
Date:   Thu Aug 15 11:53:10 2024 -0400

c++: fix ICE in convert_nontype_argument [PR116384]

Here we ICE since r14-8291 in C++11/C++14 modes.  Fortunately
this is an easy one.

The important bit of r14-8291 is this:

@@ -20056,9 +20071,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
RETURN (retval);
  }
if (IMPLICIT_CONV_EXPR_NONTYPE_ARG (t))
- /* We'll pass this to convert_nontype_argument again, we don't need
-to actually perform any conversion here.  */
- RETURN (expr);
+ {
+   tree r = convert_nontype_argument (type, expr, complain);
+   if (r == NULL_TREE)
+ r = error_mark_node;
+   RETURN (r);
+ }

which obviously means that instead of returning right away we go
to convert_nontype_argument.  When type is error_mark_node and we're
in C++17, in convert_nontype_argument we go down this path:

  else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
   || cxx_dialect >= cxx17)
{
  expr = build_converted_constant_expr (type, expr, complain);
  if (expr == error_mark_node)
return (complain & tf_error) ? NULL_TREE : error_mark_node;
  // ...
}

but pre-C++17, we take a different route and end up crashing on
gcc_unreachable.

It would of course also work to check for error_mark_node early in
build_converted_constant_expr.

PR c++/116384

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Bail if tsubst
returns error_mark_node.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/vt-116384.C: New test.

Diff:
---
 gcc/cp/pt.cc   |  2 ++
 gcc/testsuite/g++.dg/cpp0x/vt-116384.C | 26 ++
 2 files changed, 28 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8725a5eeb3f..684ee0c8a60 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20217,6 +20217,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 case IMPLICIT_CONV_EXPR:
   {
tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+   if (type == error_mark_node)
+ RETURN (error_mark_node);
tree expr = RECUR (TREE_OPERAND (t, 0));
if (dependent_type_p (type) || type_dependent_expression_p (expr))
  {
diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-116384.C 
b/gcc/testsuite/g++.dg/cpp0x/vt-116384.C
new file mode 100644
index 000..54d7f0774c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/vt-116384.C
@@ -0,0 +1,26 @@
+// PR c++/116384
+// { dg-do compile { target c++11 } }
+
+namespace a {
+template  struct c;
+template  struct d;
+}
+namespace e {
+namespace g {
+template  using h = void;
+template  class, typename...> struct detector {};
+template  class i, typename... args>
+struct detector>, i, args...>;
+}
+template  class i, typename... args>
+using j = g::detector;
+template  using l = typename a::c::m;
+template  struct conjunction;
+namespace g {
+template  using n = l>::p>;
+}
+template  = true> class o;
+}
+struct r;
+template  using q = e::o;
+void s() { e::j f; }


[gcc r15-2920] c++: ICE with NSDMIs and fn arguments [PR116015]

2024-08-14 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d91b6c93f98cac71f5588d73191d08ad788e600c

commit r15-2920-gd91b6c93f98cac71f5588d73191d08ad788e600c
Author: Marek Polacek 
Date:   Fri Aug 9 16:14:18 2024 -0400

c++: ICE with NSDMIs and fn arguments [PR116015]

The problem in this PR is that we ended up with

  {.rows=(&)->n,
   .outer_stride=(&)->rows}

that is, two PLACEHOLDER_EXPRs for different types on the same level
in one { }.  That should not happen; we may, for instance, neglect to
replace a PLACEHOLDER_EXPR due to CONSTRUCTOR_PLACEHOLDER_BOUNDARY on
the constructor.

The same problem happened in PR100252, which I fixed by introducing
replace_placeholders_for_class_temp_r.  That didn't work here, though,
because r_p_for_c_t_r only works for non-eliding TARGET_EXPRs: replacing
a PLACEHOLDER_EXPR with a temporary that is going to be elided will
result in a crash in gimplify_var_or_parm_decl when it encounters such
a loose decl.

But leaving the PLACEHOLDER_EXPRs in is also bad because then we end
up with this PR.

TARGET_EXPRs for function arguments are elided in gimplify_arg.  The
argument will get a real temporary only in get_formal_tmp_var.  One
idea was to use the temporary that is going to be elided anyway, and
then replace_decl it with the real object once we get it.  But that
didn't work out: one problem is that we elide the TARGET_EXPR for an
argument before we create the real temporary for the argument, and
when we get it, the context that this was a TARGET_EXPR for an argument
has been lost.  We're also in the middle end territory now, even though
this is a C++-specific problem.

A solution is to simply stop eliding TARGET_EXPRs whose initializer is
a CONSTRUCTOR.  Such copies can't be (at the moment) elided anyway.  But
not eliding all TARGET_EXPRs would be a pessimization.

PR c++/116015

gcc/cp/ChangeLog:

* call.cc (convert_for_arg_passing): Don't set_target_expr_eliding
when the TARGET_EXPR initializer is a CONSTRUCTOR.

gcc/ChangeLog:

* gimplify.cc (gimplify_arg): Do not strip a TARGET_EXPR whose
initializer is a CONSTRUCTOR.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/nsdmi-aggr23.C: New test.

Diff:
---
 gcc/cp/call.cc|  7 +--
 gcc/gimplify.cc   | 17 -
 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr23.C | 26 ++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 94015db4e650..0fe679aae9fe 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9468,8 +9468,11 @@ convert_for_arg_passing (tree type, tree val, 
tsubst_flags_t complain)
   if (complain & tf_warning)
 warn_for_address_of_packed_member (type, val);
 
-  /* gimplify_arg elides TARGET_EXPRs that initialize a function argument.  */
-  if (SIMPLE_TARGET_EXPR_P (val))
+  /* gimplify_arg elides TARGET_EXPRs that initialize a function argument,
+ unless the initializer is a CONSTRUCTOR.  In that case, we fail to
+ elide the copy anyway.  See that function for more information.  */
+  if (SIMPLE_TARGET_EXPR_P (val)
+  && TREE_CODE (TARGET_EXPR_INITIAL (val)) != CONSTRUCTOR)
 set_target_expr_eliding (val);
 
   return val;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 71cc6c38d807..26a216e151d6 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -3760,7 +3760,22 @@ gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t 
call_location,
{
  tree init = TARGET_EXPR_INITIAL (*arg_p);
  if (init
- && !VOID_TYPE_P (TREE_TYPE (init)))
+ && !VOID_TYPE_P (TREE_TYPE (init))
+ /* Currently, due to c++/116015, it is not desirable to
+strip a TARGET_EXPR whose initializer is a {}.  The
+problem is that if we do elide it, we also have to
+replace all the occurrences of the slot temporary in the
+initializer with the temporary created for the argument.
+But we do not have that temporary yet so the replacement
+would be quite awkward and it might be needed to resort
+back to a PLACEHOLDER_EXPR.  Note that stripping the
+TARGET_EXPR wouldn't help anyway, as gimplify_expr would
+just allocate a temporary to store the CONSTRUCTOR into.
+(FIXME PR116375.)
+
+See convert_for_arg_passing for the C++ code that marks
+the TARGET_EXPR as eliding or not.  */
+ && TREE_CODE (init) != CONSTRUCTOR)
*arg_p = init;
}
 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr23.C 
b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr23.C
new file mode 100644
index ..2f5b8ca97bf7
--- /dev/null
+++ b/gcc/t

[gcc r15-2762] c++: further concept_check_p clean-up

2024-08-06 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:68e269092ee405832998b735a796c1953039d5f3

commit r15-2762-g68e269092ee405832998b735a796c1953039d5f3
Author: Marek Polacek 
Date:   Tue Aug 6 09:34:02 2024 -0400

c++: further concept_check_p clean-up

Patrick noticed a few more concept_check_p checks that can be removed
now.

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_call_expression): Remove concept_check_p 
check.
(cxx_eval_outermost_constant_expr): Likewise.
* cp-gimplify.cc (cp_genericize_r) : Likewise.
* except.cc (check_noexcept_r): Likewise.

Diff:
---
 gcc/cp/constexpr.cc   | 20 ++--
 gcc/cp/cp-gimplify.cc |  9 -
 gcc/cp/except.cc  |  2 --
 3 files changed, 6 insertions(+), 25 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8d994f0ee536..b0adbb9036d9 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -2797,10 +2797,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
  value_cat lval,
  bool *non_constant_p, bool *overflow_p)
 {
-  /* Handle concept checks separately.  */
-  if (concept_check_p (t))
-return evaluate_concept_check (t);
-
   location_t loc = cp_expr_loc_or_input_loc (t);
   tree fun = get_function_named_in_call (t);
   constexpr_call new_call
@@ -8774,16 +8770,12 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
   || TREE_CODE (t) == AGGR_INIT_EXPR
   || TREE_CODE (t) == TARGET_EXPR))
 {
-  /* For non-concept checks, determine if it is consteval.  */
-  if (!concept_check_p (t))
-   {
- tree x = t;
- if (TREE_CODE (x) == TARGET_EXPR)
-   x = TARGET_EXPR_INITIAL (x);
- tree fndecl = cp_get_callee_fndecl_nofold (x);
- if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
-   is_consteval = true;
-   }
+  tree x = t;
+  if (TREE_CODE (x) == TARGET_EXPR)
+   x = TARGET_EXPR_INITIAL (x);
+  tree fndecl = cp_get_callee_fndecl_nofold (x);
+  if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+   is_consteval = true;
 }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
 {
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 0c589eeaaec4..003e68f1ea72 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -2092,15 +2092,6 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
   break;
 
 case CALL_EXPR:
-  /* Evaluate function concept checks instead of treating them as
-normal functions.  */
-  if (concept_check_p (stmt))
-   {
- *stmt_p = evaluate_concept_check (stmt);
- * walk_subtrees = 0;
- break;
-   }
-
   if (!wtd->no_sanitize_p
  && sanitize_flags_p ((SANITIZE_NULL
| SANITIZE_ALIGNMENT | SANITIZE_VPTR)))
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 3c69ab695028..0231bd2507d5 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -1074,8 +1074,6 @@ check_noexcept_r (tree *tp, int *walk_subtrees, void *)
 
  We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */
   tree fn = cp_get_callee (t);
-  if (concept_check_p (fn))
-   return NULL_TREE;
   tree type = TREE_TYPE (fn);
   gcc_assert (INDIRECT_TYPE_P (type));
   type = TREE_TYPE (type);


[gcc r15-2735] c++: remove function/var concepts code

2024-08-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:935e82248873c3798d4ede742a75ad10e99257ad

commit r15-2735-g935e82248873c3798d4ede742a75ad10e99257ad
Author: Marek Polacek 
Date:   Thu Aug 1 15:39:10 2024 -0400

c++: remove function/var concepts code

This patch removes vestigial Concepts TS code as discussed in
.

In particular, it removes code related to function/variable concepts.
That includes variable_concept_p and function_concept_p, which then
cascades into removing DECL_DECLARED_CONCEPT_P etc.  So I think we
no longer need to say "standard concept" since there are no non-standard
ones anymore.

I've added two new errors saying that "variable/function concepts are
no longer supported".

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_constant_expression): Don't call
unpack_concept_check.  Add a concept_check_p assert.  Remove
function_concept_p code.
* constraint.cc (check_constraint_atom): Remove function concepts 
code.
(unpack_concept_check): Remove.
(get_concept_check_template): Remove Concepts TS code.
(resolve_function_concept_overload): Remove.
(resolve_function_concept_check): Remove.
(resolve_concept_check): Remove Concepts TS code.
(get_returned_expression): Remove.
(get_variable_initializer): Remove.
(get_concept_definition): Remove Concepts TS code.
(normalize_concept_check): Likewise.
(build_function_check): Remove.
(build_variable_check): Remove.
(build_standard_check): Use concept_definition_p instead of
standard_concept_p.
(build_concept_check): Remove variable_concept_p/function_concept_p
code.
(build_concept_id): Simplify.
(build_type_constraint): Likewise.
(placeholder_extract_concept_and_args): Likewise.
(satisfy_nondeclaration_constraints): Likewise.
(check_function_concept): Remove.
(get_constraint_error_location): Remove Concepts TS code.
* cp-tree.h (DECL_DECLARED_CONCEPT_P): Remove.
(check_function_concept): Remove.
(unpack_concept_check): Remove.
(standard_concept_p): Remove.
(variable_concept_p): Remove.
(function_concept_p): Remove.
(concept_definition_p): Simplify.
(concept_check_p): Don't check for CALL_EXPR.
* decl.cc (check_concept_refinement): Remove.
(duplicate_decls): Remove check_concept_refinement code.
(is_concept_var): Remove.
(cp_finish_decl): Remove is_concept_var.
(check_concept_fn): Remove.
(grokfndecl): Give an error about function concepts not being 
supported
anymore.  Remove unused code.
(grokvardecl): Give an error about variable concepts not being
supported anymore.
(finish_function): Remove DECL_DECLARED_CONCEPT_P code.
* decl2.cc (min_vis_expr_r): Use concept_definition_p instead of
standard_concept_p.
(maybe_instantiate_decl): Remove DECL_DECLARED_CONCEPT_P check.
(mark_used): Likewise.
* error.cc (dump_simple_decl): Use concept_definition_p instead of
standard_concept_p.
(dump_function_decl): Remove DECL_DECLARED_CONCEPT_P code.
(print_concept_check_info): Don't call unpack_concept_check.  
Simplify.
* mangle.cc (write_type_constraint): Likewise.
* parser.cc (cp_parser_nested_name_specifier_opt): Remove
function_concept_p code.  Only check concept_definition_p, not
variable_concept_p/standard_concept_p.
(add_debug_begin_stmt): Remove DECL_DECLARED_CONCEPT_P code.
(cp_parser_template_declaration_after_parameters): Remove a stale
comment.
* pt.cc (check_explicit_specialization): Remove
DECL_DECLARED_CONCEPT_P code.
(process_partial_specialization): Remove variable_concept_p code.
(lookup_template_variable): Likewise.
(tsubst_expr) : Remove Concepts TS code and 
simplify.
(do_decl_instantiation): Remove DECL_DECLARED_CONCEPT_P code.
(instantiate_decl): Likewise.
(placeholder_type_constraint_dependent_p): Don't call
unpack_concept_check.  Add a concept_check_p assert.
(convert_generic_types_to_packs): Likewise.
* semantics.cc (finish_call_expr): Remove Concepts TS code and 
simplify.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/decl-diagnose.C: Adjust dg-error.
* g++.dg/concepts/fn-concept2.C: Likewise.
* g++.dg/concepts/pr71128.C: Likewise.
* g++.dg/concepts/var-concept6.C: Likewise.

[gcc r15-2727] c++: fix -Wdangling-reference false positive [PR115987]

2024-08-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:34d947134403e7482ba4f153d8faabee0bc4933e

commit r15-2727-g34d947134403e7482ba4f153d8faabee0bc4933e
Author: Marek Polacek 
Date:   Wed Jul 31 17:33:55 2024 -0400

c++: fix -Wdangling-reference false positive [PR115987]

This fixes another false positive.  When a function is taking a
temporary of scalar type that couldn't be bound to the return type
of the function, don't warn, such a program would be ill-formed.

Thanks to Jonathan for reporting the problem.

PR c++/115987

gcc/cp/ChangeLog:

* call.cc (do_warn_dangling_reference): Don't consider a
temporary with a scalar type that cannot bind to the return type.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-no-dangling6.C: Adjust.
* g++.dg/ext/attr-no-dangling7.C: Likewise.
* g++.dg/warn/Wdangling-reference22.C: New test.

Diff:
---
 gcc/cp/call.cc| 14 --
 gcc/testsuite/g++.dg/ext/attr-no-dangling6.C  | 22 +++---
 gcc/testsuite/g++.dg/ext/attr-no-dangling7.C  |  8 
 gcc/testsuite/g++.dg/warn/Wdangling-reference22.C | 19 +++
 4 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 40cb582acc70..a75e2e5e3afd 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -14290,8 +14290,18 @@ do_warn_dangling_reference (tree expr, bool arg_p)
/* Recurse to see if the argument is a temporary.  It could also
   be another call taking a temporary and returning it and
   initializing this reference parameter.  */
-   if (do_warn_dangling_reference (arg, /*arg_p=*/true))
- return expr;
+   if ((arg = do_warn_dangling_reference (arg, /*arg_p=*/true)))
+ {
+   /* If we know the temporary could not bind to the return type,
+  don't warn.  This is for scalars only because for classes
+  we can't be sure we are not returning its sub-object.  */
+   if (SCALAR_TYPE_P (TREE_TYPE (arg))
+   && TYPE_REF_P (rettype)
+   && !reference_related_p (TREE_TYPE (arg),
+TREE_TYPE (rettype)))
+ continue;
+   return expr;
+ }
  /* Don't warn about member functions like:
  std::any a(...);
  S& s = a.emplace({0}, 0);
diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C 
b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C
index 235a5fd86c55..5b349e8e6827 100644
--- a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C
+++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C
@@ -12,26 +12,26 @@ struct SF { static constexpr bool value = false; };
 
 template
 [[gnu::no_dangling(T::value)]]
-const X& get (const int& i)
+const X& get (const int& i, const X&)
 {
return i == 0 ? x1 : x2;
 }
 
 template
 [[gnu::no_dangling(B)]]
-const X& foo (const int& i)
+const X& foo (const int& i, const X&)
 {
return i == 0 ? x1 : x2;
 }
 
 [[gnu::no_dangling(val ())]]
-const X& bar (const int& i)
+const X& bar (const int& i, const X&)
 {
return i == 0 ? x1 : x2;
 }
 
 [[gnu::no_dangling(!val ())]]
-const X& baz (const int& i)
+const X& baz (const int& i, const X&)
 {
return i == 0 ? x1 : x2;
 }
@@ -52,13 +52,13 @@ auto gety() -> Span;
 void
 test ()
 {
-  [[maybe_unused]] const X& x1 = get (10);   // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x2 = get (10);   // { dg-warning "dangling" }
-  [[maybe_unused]] const X& x3 = foo (10);  // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x4 = foo (10); // { dg-warning "dangling" }
-  [[maybe_unused]] const X& x7 = foo<> (10); // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x5 = bar (10);   // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x6 = baz (10);   // { dg-warning "dangling" }
+  [[maybe_unused]] const X& x1 = get (10, X{});  // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x2 = get (10, X{});  // { dg-warning 
"dangling" }
+  [[maybe_unused]] const X& x3 = foo (10, X{});  // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x4 = foo (10, X{}); // { dg-warning 
"dangling" }
+  [[maybe_unused]] const X& x7 = foo<> (10, X{});// { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x5 = bar (10, X{});  // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x6 = baz (10, X{});  // { dg-warning 
"dangling" }
 
   [[maybe_unused]] const auto &b1 = geti()[0];   // { dg-bogus "dangling" }
   [[maybe_unused]] const auto &b2 = gety()[0];   // { dg-warning "dangling" }
diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C 
b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C
index 3c392ed409f8..a5fb809e6bdb 100644
--- a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C
+++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C
@@ -16,16 +1

[gcc r15-2703] c++: Move -Wdangling-reference to -Wextra

2024-08-02 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:5ebfaf2d4994c124ce81aa0abd7eaa1529644749

commit r15-2703-g5ebfaf2d4994c124ce81aa0abd7eaa1529644749
Author: Marek Polacek 
Date:   Thu Aug 1 10:35:38 2024 -0400

c++: Move -Wdangling-reference to -Wextra

Despite a number of mitigations (don't warn for std::span-like classes,
lambdas, adding [[gnu::no_dangling]], etc.), the warning still seems to
cause some grief.  Let's move the warning to -Wextra, then.

gcc/c-family/ChangeLog:

* c.opt (Wdangling-reference): Move from -Wall to -Wextra.

gcc/ChangeLog:

* doc/invoke.texi: Document that -Wdangling-reference is
enabled by -Wextra.

Diff:
---
 gcc/c-family/c.opt  | 2 +-
 gcc/doc/invoke.texi | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index a52682d835ce..979f17a7e323 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -604,7 +604,7 @@ C ObjC C++ ObjC++ Joined RejectNegative UInteger 
Var(warn_dangling_pointer) Warn
 Warn for uses of pointers to auto variables whose lifetime has ended.
 
 Wdangling-reference
-C++ ObjC++ Var(warn_dangling_reference) Warning LangEnabledBy(C++ ObjC++, Wall)
+C++ ObjC++ Var(warn_dangling_reference) Warning LangEnabledBy(C++ ObjC++, 
Wextra)
 Warn when a reference is bound to a temporary whose lifetime has ended.
 
 Wdate-time
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 54ecd9a00eb4..0fe99ca8ef6e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3962,7 +3962,7 @@ that has a pointer data member and a trivial destructor.
 The warning can be disabled by using the @code{gnu::no_dangling} attribute
 (@pxref{C++ Attributes}).
 
-This warning is enabled by @option{-Wall}.
+This warning is enabled by @option{-Wextra}.
 
 @opindex Wdelete-non-virtual-dtor
 @opindex Wno-delete-non-virtual-dtor
@@ -6481,6 +6481,7 @@ name is still supported, but the newer name is more 
descriptive.)
 -Wcalloc-transposed-args
 -Wcast-function-type
 -Wclobbered
+-Wdangling-reference @r{(C++ only)}
 -Wdeprecated-copy @r{(C++ and Objective-C++ only)}
 -Wempty-body
 -Wenum-conversion @r{(only for C/ObjC)}


[gcc r15-2695] c++: DR882, main cannot be deleted [PR116169]

2024-08-02 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:a790828ccb3b06a7771f871651e7b54d13c3a168

commit r15-2695-ga790828ccb3b06a7771f871651e7b54d13c3a168
Author: Marek Polacek 
Date:   Thu Aug 1 11:32:26 2024 -0400

c++: DR882, main cannot be deleted [PR116169]

This DR clarifies that "int main() = delete;" is ill-formed.

PR c++/116169

gcc/cp/ChangeLog:

* decl.cc (cp_finish_decl): Disallow deleting ::main.

gcc/testsuite/ChangeLog:

* g++.dg/DRs/dr882.C: New test.

Diff:
---
 gcc/cp/decl.cc   | 26 ++
 gcc/testsuite/g++.dg/DRs/dr882.C |  5 +
 2 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 279af21eed03..687ae6937f53 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8649,15 +8649,25 @@ cp_finish_decl (tree decl, tree init, bool 
init_const_expr_p,
  && TREE_TYPE (init) == ridpointers[(int)RID_DELETE]))
{
  /* FIXME check this is 1st decl.  */
- DECL_DELETED_FN (decl) = 1;
- DECL_DECLARED_INLINE_P (decl) = 1;
- DECL_INITIAL (decl)
-   = TREE_CODE (init) == STRING_CST ? init : error_mark_node;
- FOR_EACH_CLONE (clone, decl)
+ if (UNLIKELY (DECL_MAIN_P (decl)))
{
- DECL_DELETED_FN (clone) = 1;
- DECL_DECLARED_INLINE_P (clone) = 1;
- DECL_INITIAL (clone) = DECL_INITIAL (decl);
+ /* [basic.start.main]/3: A program that defines main as deleted
+is ill-formed.  */
+ error ("%<::main%> cannot be deleted");
+ DECL_INITIAL (decl) = NULL_TREE;
+   }
+ else
+   {
+ DECL_DELETED_FN (decl) = 1;
+ DECL_DECLARED_INLINE_P (decl) = 1;
+ DECL_INITIAL (decl)
+   = TREE_CODE (init) == STRING_CST ? init : error_mark_node;
+ FOR_EACH_CLONE (clone, decl)
+   {
+ DECL_DELETED_FN (clone) = 1;
+ DECL_DECLARED_INLINE_P (clone) = 1;
+ DECL_INITIAL (clone) = DECL_INITIAL (decl);
+   }
}
  init = NULL_TREE;
}
diff --git a/gcc/testsuite/g++.dg/DRs/dr882.C b/gcc/testsuite/g++.dg/DRs/dr882.C
new file mode 100644
index ..c41cf7416a29
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr882.C
@@ -0,0 +1,5 @@
+// DR882 - Defining main as deleted
+// PR c++/116169
+// { dg-do compile { target c++11 } }
+
+int main() = delete; // { dg-error "cannot be deleted" }


[gcc r15-2435] c++: array new with value-initialization, again [PR115645]

2024-07-31 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:bbc9c0423ca754e8e6ff80e08948ff52986337a0

commit r15-2435-gbbc9c0423ca754e8e6ff80e08948ff52986337a0
Author: Marek Polacek 
Date:   Wed Jul 17 15:44:26 2024 -0400

c++: array new with value-initialization, again [PR115645]

Unfortunately, my r15-1946 fix broke the attached testcase; the
constexpr evaluation reported an error about not being able to
evaluate the code emitted by build_vec_init.  Jason figured out
it's because we were wrongly setting try_const to false, where
in fact it should have been true.  Value-initialization of scalars
is constexpr, so we should check that alongside of
type_has_constexpr_default_constructor.

PR c++/115645

gcc/cp/ChangeLog:

* init.cc (build_vec_init): When initializing a scalar type, try to
create a constant initializer.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/init.cc   |  5 +++-
 gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C | 38 
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index e9561c146d7b..de82152bd1d3 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4724,7 +4724,10 @@ build_vec_init (tree base, tree maxindex, tree init,
&& TREE_CONSTANT (maxindex)
&& (init ? TREE_CODE (init) == CONSTRUCTOR
: (type_has_constexpr_default_constructor
-  (inner_elt_type)))
+  (inner_elt_type)
+  /* Value-initialization of scalars is constexpr.  */
+  || (explicit_value_init_p
+  && SCALAR_TYPE_P (inner_elt_type
&& (literal_type_p (inner_elt_type)
|| TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type)));
   vec *const_vec = NULL;
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C
new file mode 100644
index ..1abbef18fae3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C
@@ -0,0 +1,38 @@
+// PR c++/115645
+// { dg-do compile { target c++20 } }
+
+using size_t = decltype(sizeof(0));
+
+void* operator new(size_t, void* p) { return p; }
+void* operator new[](size_t, void* p) { return p; }
+
+#define VERIFY(C) if (!(C)) throw
+
+namespace std {
+  template
+constexpr T* construct_at(T* p)
+{
+  if constexpr (__is_array(T))
+return ::new((void*)p) T[1]();
+  else
+return ::new((void*)p) T();
+}
+}
+
+constexpr void
+test_array()
+{
+  int arr[1] { 99 };
+  std::construct_at(&arr);
+  VERIFY( arr[0] == 0 );
+
+  union U {
+long long x = -1;
+int arr[4];
+  } u;
+
+  auto p = std::construct_at(&u.arr);
+  VERIFY( (*p)[0] == 0 );
+}
+
+static_assert( [] { test_array(); return true; }() );


[gcc r15-2235] doc: add missing @option for musttail

2024-07-23 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:e8c40aed0f81ca8aac1ae43f140f489eda2d3a07

commit r15-2235-ge8c40aed0f81ca8aac1ae43f140f489eda2d3a07
Author: Marek Polacek 
Date:   Tue Jul 23 16:32:20 2024 -0400

doc: add missing @option for musttail

gcc/ChangeLog:

* doc/extend.texi: Add missing @option.

Diff:
---
 gcc/doc/extend.texi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b0273927b256..66c99ef7a667 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9995,8 +9995,8 @@ If the compiler cannot generate a @code{musttail} tail 
call it will report
 an error. On some targets tail calls may never be supported.
 Tail calls cannot reference locals in memory, which may affect
 builds without optimization when passing small structures, or passing
-or returning large structures. Enabling -O1 or -O2 can improve
-the success of tail calls.
+or returning large structures.  Enabling @option{-O1} or @option{-O2} can
+improve the success of tail calls.
 @end table
 
 @node Attribute Syntax


[gcc r15-2146] c++: implement DR1363 and DR1496 for __is_trivial [PR85723]

2024-07-18 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:9690fb3a43e5cf26a5fb853283d4200df312a640

commit r15-2146-g9690fb3a43e5cf26a5fb853283d4200df312a640
Author: Marek Polacek 
Date:   Tue Jun 18 16:49:24 2024 -0400

c++: implement DR1363 and DR1496 for __is_trivial [PR85723]

is_trivial was introduced in

which split POD into is_trivial and is_standard_layout.

Later came CWG 1363.  Since

  struct A {
A() = default;
A(int = 42) {}
  };

cannot be default-initialized, it should not be trivial, so the definition
of what is a trivial class changed.

Similarly, CWG 1496 concluded that

  struct B {
B() = delete;
  }:

should not be trivial either.

P0848 adjusted the definition further to say "eligible".  That means
that

  template
  struct C {
C() requires false = default;
  };

should not be trivial, either, since C::C() is not eligible.

Bug 85723 reports that we implement none of the CWGs.

I chose to fix this by using type_has_non_deleted_trivial_default_ctor
which uses locate_ctor which uses build_new_method_call, which would
be used by default-initialization as well.  With that, all __is_trivial
problems I could find in the Bugzilla are fixed, except for PR96288,
which may need changes to trivially-copyable, so I'm not messing with
that now.

I hope this has no ABI implications.  There's effort undergoing to
remove "trivial class" from the core language as it's not really
meaningful.  So the impact of this change should be pretty low except
to fix a few libstdc++ problems.

PR c++/108769
PR c++/58074
PR c++/115522
PR c++/85723

gcc/cp/ChangeLog:

* class.cc (type_has_non_deleted_trivial_default_ctor): Fix 
formatting.
* tree.cc (trivial_type_p): Instead of TYPE_HAS_TRIVIAL_DFLT, use
type_has_non_deleted_trivial_default_ctor.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wclass-memaccess.C: Add dg-warning.
* g++.dg/ext/is_trivial1.C: New test.
* g++.dg/ext/is_trivial2.C: New test.
* g++.dg/ext/is_trivial3.C: New test.
* g++.dg/ext/is_trivial4.C: New test.
* g++.dg/ext/is_trivial5.C: New test.
* g++.dg/ext/is_trivial6.C: New test.

Diff:
---
 gcc/cp/class.cc  |  3 +-
 gcc/cp/tree.cc   |  4 ++-
 gcc/testsuite/g++.dg/ext/is_trivial1.C   | 14 
 gcc/testsuite/g++.dg/ext/is_trivial2.C   | 20 
 gcc/testsuite/g++.dg/ext/is_trivial3.C   | 15 +
 gcc/testsuite/g++.dg/ext/is_trivial4.C   | 10 ++
 gcc/testsuite/g++.dg/ext/is_trivial5.C   |  8 +
 gcc/testsuite/g++.dg/ext/is_trivial6.C   | 49 
 gcc/testsuite/g++.dg/warn/Wclass-memaccess.C |  2 ++
 9 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 0ce361eb88e5..718601756ddc 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -5918,7 +5918,8 @@ type_has_virtual_destructor (tree type)
 /* True iff class TYPE has a non-deleted trivial default
constructor.  */
 
-bool type_has_non_deleted_trivial_default_ctor (tree type)
+bool
+type_has_non_deleted_trivial_default_ctor (tree type)
 {
   return TYPE_HAS_TRIVIAL_DFLT (type) && locate_ctor (type);
 }
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b1..0e32d908b060 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -4637,7 +4637,9 @@ trivial_type_p (const_tree t)
   t = strip_array_types (CONST_CAST_TREE (t));
 
   if (CLASS_TYPE_P (t))
-return (TYPE_HAS_TRIVIAL_DFLT (t)
+/* A trivial class is a class that is trivially copyable and has one or
+   more eligible default constructors, all of which are trivial.  */
+return (type_has_non_deleted_trivial_default_ctor (CONST_CAST_TREE (t))
&& trivially_copyable_p (t));
   else
 return scalarish_type_p (t);
diff --git a/gcc/testsuite/g++.dg/ext/is_trivial1.C 
b/gcc/testsuite/g++.dg/ext/is_trivial1.C
new file mode 100644
index ..60ce48edfe9e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivial1.C
@@ -0,0 +1,14 @@
+// PR c++/108769
+// { dg-do compile { target c++20 } }
+
+template 
+struct S {
+S() requires false = default;
+};
+static_assert(!__is_trivial(S));
+
+template 
+struct R {
+R() requires true = default;
+};
+static_assert(__is_trivial(R));
diff --git a/gcc/testsuite/g++.dg/ext/is_trivial2.C 
b/gcc/testsuite/g++.dg/ext/is_trivial2.C
new file mode 100644
index ..e7ecc74831a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivial2.C
@@ -0,0 +1,20 @@
+// PR c++/58074
+// { dg-do compile { target c++11 } }
+
+struct Trivial
+{
+  Trivial() = delete;
+};
+
+struct NonTrivi

[gcc r14-10461] eh: ICE with std::initializer_list and ASan [PR115865]

2024-07-18 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:493035c8780cd510a680a791d0c7f94368164352

commit r14-10461-g493035c8780cd510a680a791d0c7f94368164352
Author: Marek Polacek 
Date:   Thu Jul 11 15:57:43 2024 -0400

eh: ICE with std::initializer_list and ASan [PR115865]

Here we ICE with -fsanitize=address on

  std::initializer_list x = { 1, 2, 3 };

since r14-8681, which removed .ASAN_MARK calls on TREE_STATIC variables.
That means that lower_try_finally now instead of

  try
{
  .ASAN_MARK (UNPOISON, &C.0, 12);
  x = {};
  x._M_len = 3;
  x._M_array = &C.0;
}
  finally
{
  .ASAN_MARK (POISON, &C.0, 12);
}

gets:

  try
{
  x = {};
  x._M_len = 3;
  x._M_array = &C.0;
}
  finally
{

}

and we ICE on the empty finally in lower_try_finally_onedest while
getting get_eh_else.

PR c++/115865

gcc/ChangeLog:

* tree-eh.cc (get_eh_else): Check that the result of
gimple_seq_first_stmt is non-null.

gcc/testsuite/ChangeLog:

* g++.dg/asan/initlist2.C: New test.

Co-authored-by: Jakub Jelinek  
(cherry picked from commit 1e60a6abfece40c7bf55d6ca0a439078d3f5159a)

Diff:
---
 gcc/testsuite/g++.dg/asan/initlist2.C | 16 
 gcc/tree-eh.cc|  2 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/asan/initlist2.C 
b/gcc/testsuite/g++.dg/asan/initlist2.C
new file mode 100644
index ..bce5410be339
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/initlist2.C
@@ -0,0 +1,16 @@
+// PR c++/115865
+// { dg-do compile }
+// { dg-options "-fsanitize=address" }
+
+typedef decltype(sizeof(char)) size_t;
+
+namespace std {
+template  class initializer_list {
+  int *_M_array;
+  size_t _M_len;
+};
+}
+
+int main() {
+  std::initializer_list x = { 1, 2, 3 };
+}
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index a776ad5c92ba..9609bdc0d9b7 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -950,7 +950,7 @@ static inline geh_else *
 get_eh_else (gimple_seq finally)
 {
   gimple *x = gimple_seq_first_stmt (finally);
-  if (gimple_code (x) == GIMPLE_EH_ELSE)
+  if (x && gimple_code (x) == GIMPLE_EH_ELSE)
 {
   gcc_assert (gimple_seq_singleton_p (finally));
   return as_a  (x);


[gcc r15-2141] eh: ICE with std::initializer_list and ASan [PR115865]

2024-07-18 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:1e60a6abfece40c7bf55d6ca0a439078d3f5159a

commit r15-2141-g1e60a6abfece40c7bf55d6ca0a439078d3f5159a
Author: Marek Polacek 
Date:   Thu Jul 11 15:57:43 2024 -0400

eh: ICE with std::initializer_list and ASan [PR115865]

Here we ICE with -fsanitize=address on

  std::initializer_list x = { 1, 2, 3 };

since r14-8681, which removed .ASAN_MARK calls on TREE_STATIC variables.
That means that lower_try_finally now instead of

  try
{
  .ASAN_MARK (UNPOISON, &C.0, 12);
  x = {};
  x._M_len = 3;
  x._M_array = &C.0;
}
  finally
{
  .ASAN_MARK (POISON, &C.0, 12);
}

gets:

  try
{
  x = {};
  x._M_len = 3;
  x._M_array = &C.0;
}
  finally
{

}

and we ICE on the empty finally in lower_try_finally_onedest while
getting get_eh_else.

PR c++/115865

gcc/ChangeLog:

* tree-eh.cc (get_eh_else): Check that the result of
gimple_seq_first_stmt is non-null.

gcc/testsuite/ChangeLog:

* g++.dg/asan/initlist2.C: New test.

Co-authored-by: Jakub Jelinek  

Diff:
---
 gcc/testsuite/g++.dg/asan/initlist2.C | 16 
 gcc/tree-eh.cc|  2 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/asan/initlist2.C 
b/gcc/testsuite/g++.dg/asan/initlist2.C
new file mode 100644
index ..bce5410be339
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/initlist2.C
@@ -0,0 +1,16 @@
+// PR c++/115865
+// { dg-do compile }
+// { dg-options "-fsanitize=address" }
+
+typedef decltype(sizeof(char)) size_t;
+
+namespace std {
+template  class initializer_list {
+  int *_M_array;
+  size_t _M_len;
+};
+}
+
+int main() {
+  std::initializer_list x = { 1, 2, 3 };
+}
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index a776ad5c92ba..9609bdc0d9b7 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -950,7 +950,7 @@ static inline geh_else *
 get_eh_else (gimple_seq finally)
 {
   gimple *x = gimple_seq_first_stmt (finally);
-  if (gimple_code (x) == GIMPLE_EH_ELSE)
+  if (x && gimple_code (x) == GIMPLE_EH_ELSE)
 {
   gcc_assert (gimple_seq_singleton_p (finally));
   return as_a  (x);


[gcc r15-2108] c++: wrong error initializing empty class [PR115900]

2024-07-17 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d890b04197fb0ddba4fbfb32f88e266fa27e02f3

commit r15-2108-gd890b04197fb0ddba4fbfb32f88e266fa27e02f3
Author: Marek Polacek 
Date:   Wed Jul 17 11:19:32 2024 -0400

c++: wrong error initializing empty class [PR115900]

In r14-409, we started handling empty bases first in cxx_fold_indirect_ref_1
so that we don't need to recurse and waste time.

This caused a bogus "modifying a const object" error.  I'm appending my
analysis from the PR, but basically, cxx_fold_indirect_ref now returns
a different object than before, and we mark the wrong thing as const,
but since we're initializing an empty object, we should avoid setting
the object constness.

~~
Pre-r14-409: we're evaluating the call to C::C(), which is in the body of
B::B(), which is the body of D::D(&d):

  C::C ((struct C *) this, NON_LVALUE_EXPR <0>)

It's a ctor so we get here:

 3118   /* Remember the object we are constructing or destructing.  */
 3119   tree new_obj = NULL_TREE;
 3120   if (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))
 3121 {
 3122   /* In a cdtor, it should be the first `this' argument.
 3123  At this point it has already been evaluated in the call
 3124  to cxx_bind_parameters_in_call.  */
 3125   new_obj = TREE_VEC_ELT (new_call.bindings, 0);

new_obj=(struct C *) &d.D.2656

 3126   new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), 
new_obj);

new_obj=d.D.2656.D.2597

We proceed to evaluate the call, then we get here:

 3317   /* At this point, the object's constructor will have run, so
 3318  the object is no longer under construction, and its 
possible
 3319  'const' semantics now apply.  Make a note of this fact by
 3320  marking the CONSTRUCTOR TREE_READONLY.  */
 3321   if (new_obj && DECL_CONSTRUCTOR_P (fun))
 3322 cxx_set_object_constness (ctx, new_obj, 
/*readonly_p=*/true,
 3323   non_constant_p, overflow_p);

new_obj is still d.D.2656.D.2597, its type is "C", cxx_set_object_constness
doesn't set anything as const.  This is fine.

After r14-409: on line 3125, new_obj is (struct C *) &d.D.2656 as before,
but we go to cxx_fold_indirect_ref_1:

 5739   if (is_empty_class (type)
 5740   && CLASS_TYPE_P (optype)
 5741   && lookup_base (optype, type, ba_any, NULL, tf_none, off))
 5742 {
 5743   if (empty_base)
 5744 *empty_base = true;
 5745   return op;

type is C, which is an empty class; optype is "const D", and C is a base of 
D.
So we return the VAR_DECL 'd'.  Then we get to cxx_set_object_constness with
object=d, which is const, so we mark the constructor READONLY.

Then we're evaluating A::A() which has

  ((A*)this)->data = 0;

we evaluate the LHS to d.D.2656.a, for which the initializer is
{.D.2656={.a={.data=}}} which is TREE_READONLY and 'd' is const, so we think
we're modifying a const object and fail the constexpr evaluation.

PR c++/115900

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_call_expression): Set new_obj to NULL_TREE
if cxx_fold_indirect_ref set empty_base to true.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/constexpr.cc   | 14 ++
 gcc/testsuite/g++.dg/cpp2a/constexpr-init23.C | 22 ++
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f12b1dfc46d8..abd3b04ea7f2 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3123,10 +3123,16 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
tree t,
 At this point it has already been evaluated in the call
 to cxx_bind_parameters_in_call.  */
   new_obj = TREE_VEC_ELT (new_call.bindings, 0);
-  new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj);
-
-  if (ctx->call && ctx->call->fundef
- && DECL_CONSTRUCTOR_P (ctx->call->fundef->decl))
+  bool empty_base = false;
+  new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj,
+  &empty_base);
+  /* If we're initializing an empty class, don't set constness, because
+cxx_fold_indirect_ref will return the wrong object to set constness
+of.  */
+  if (empty_base)
+   new_obj = NULL_TREE;
+  else if (ctx->call && ctx->call->fundef
+  && DECL_CONSTRUCTOR_P (ctx->call->fundef->decl))
{
  tree cur_obj = TREE_VEC_ELT (ctx->call->bindings, 0);
  STRIP_NOPS (cur_obj);
diff --git a/gcc/testsuite/g++.dg/cp

[gcc r15-2010] doc: remove @opindex for fconcepts-ts

2024-07-12 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:b3d4a021eff6353a099f800857d3080a7cd27003

commit r15-2010-gb3d4a021eff6353a099f800857d3080a7cd27003
Author: Marek Polacek 
Date:   Fri Jul 12 14:40:59 2024 -0400

doc: remove @opindex for fconcepts-ts

We're getting complaints from the CI system about this removed option.
I suspect I should have removed the @opindex and @itemx for it.  This
patch does that.

gcc/ChangeLog:

* doc/invoke.texi: Remove @opindex and @itemx for -fconcepts-ts.

Diff:
---
 gcc/doc/invoke.texi | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 4850c7379bfa..d10796cabd69 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3217,16 +3217,14 @@ exhaustion is signalled by throwing 
@code{std::bad_alloc}.  See also
 @samp{new (nothrow)}.
 
 @opindex fconcepts
-@opindex fconcepts-ts
 @item -fconcepts
-@itemx -fconcepts-ts
 Enable support for the C++ Concepts feature for constraining template
 arguments.  With @option{-std=c++20} and above, Concepts are part of
 the language standard, so @option{-fconcepts} defaults to on.
 
 Some constructs that were allowed by the earlier C++ Extensions for
 Concepts Technical Specification, ISO 19217 (2015), but didn't make it
-into the standard, can additionally be enabled by
+into the standard, could additionally be enabled by
 @option{-fconcepts-ts}.  The option @option{-fconcepts-ts} was deprecated
 in GCC 14 and removed in GCC 15; users are expected to convert their code
 to C++20 concepts.


[gcc r15-1952] c: ICE with invalid sizeof [PR115642]

2024-07-10 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:0c27eade4754c13a54e265e4305182c95be1e441

commit r15-1952-g0c27eade4754c13a54e265e4305182c95be1e441
Author: Marek Polacek 
Date:   Tue Jun 25 14:55:08 2024 -0400

c: ICE with invalid sizeof [PR115642]

Here we ICE in c_expr_sizeof_expr on an erroneous expr.value.  The
code checks for expr.value == error_mark_node but here the e_m_n is
wrapped in a C_MAYBE_CONST_EXPR.  I don't think we should have created
such a tree, so let's return earlier in c_cast_expr.

PR c/115642

gcc/c/ChangeLog:

* c-typeck.cc (c_cast_expr): Return error_mark_node if build_c_cast
failed.

gcc/testsuite/ChangeLog:

* gcc.dg/noncompile/sizeof-1.c: New test.

Diff:
---
 gcc/c/c-typeck.cc  | 3 +++
 gcc/testsuite/gcc.dg/noncompile/sizeof-1.c | 7 +++
 2 files changed, 10 insertions(+)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 455dc374b481..36f88fcd03de 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -6702,6 +6702,9 @@ c_cast_expr (location_t loc, struct c_type_name 
*type_name, tree expr)
 return error_mark_node;
 
   ret = build_c_cast (loc, type, expr);
+  if (ret == error_mark_node)
+return error_mark_node;
+
   if (type_expr)
 {
   bool inner_expr_const = true;
diff --git a/gcc/testsuite/gcc.dg/noncompile/sizeof-1.c 
b/gcc/testsuite/gcc.dg/noncompile/sizeof-1.c
new file mode 100644
index ..db7e2044b113
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/noncompile/sizeof-1.c
@@ -0,0 +1,7 @@
+/* PR c/115642 */
+/* { dg-do compile } */
+
+void f (int N) {
+  int a[2][N];
+  sizeof ((int [2][N])a); /* { dg-error "cast specifies array type" } */
+}


[gcc r15-1951] c: ICE on invalid with attribute optimize [PR115549]

2024-07-10 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:4c7009735f73f59c9a635d79c048c8981310e331

commit r15-1951-g4c7009735f73f59c9a635d79c048c8981310e331
Author: Marek Polacek 
Date:   Thu Jun 27 16:39:29 2024 -0400

c: ICE on invalid with attribute optimize [PR115549]

I had this PR in my open tabs so why not go ahead and fix it.

decl_attributes gets last_decl, the last already pushed declaration,
to be used in common_handle_aligned_attribute.  In C++, we look up
the decl via find_last_decl, which returns NULL_TREE if it finds
a decl that had not been declared.  In C, we look up the decl via
lookup_last_decl which returns error_mark_node rather than NULL_TREE
in that case.

The error_mark_node causes a crash in common_handle_aligned_attribute.
We can fix this on the C FE side like in the patch below.

PR c/115549

gcc/c/ChangeLog:

* c-decl.cc (c_decl_attributes): If lookup_last_decl returns
error_mark_node, use NULL_TREE as last_decl.

gcc/testsuite/ChangeLog:

* c-c++-common/attr-aligned-2.c: New test.

Diff:
---
 gcc/c/c-decl.cc | 5 -
 gcc/testsuite/c-c++-common/attr-aligned-2.c | 8 
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 0eac266471f7..97f1d346835e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5496,8 +5496,11 @@ c_decl_attributes (tree *node, tree attributes, int 
flags)
   /* Look up the current declaration with all the attributes merged
  so far so that attributes on the current declaration that's
  about to be pushed that conflict with the former can be detected,
- diagnosed, and rejected as appropriate.  */
+ diagnosed, and rejected as appropriate.  To match the C++ FE, do
+ not pass an error_mark_node when we found an undeclared variable.  */
   tree last_decl = lookup_last_decl (*node);
+  if (last_decl == error_mark_node)
+last_decl = NULL_TREE;
   return decl_attributes (node, attributes, flags, last_decl);
 }
 
diff --git a/gcc/testsuite/c-c++-common/attr-aligned-2.c 
b/gcc/testsuite/c-c++-common/attr-aligned-2.c
new file mode 100644
index ..991b3904540b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-aligned-2.c
@@ -0,0 +1,8 @@
+/* PR c/115549 */
+/* { dg-do compile } */
+
+__attribute__((aligned,optimize(s))) /* { dg-error "not declared|undeclared" } 
*/
+int s()
+{
+  return 0;
+}


[gcc r15-1946] c++: array new with value-initialization [PR115645]

2024-07-10 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:fde96e8205f343e6471a11cc9def967bb5dd5362

commit r15-1946-gfde96e8205f343e6471a11cc9def967bb5dd5362
Author: Marek Polacek 
Date:   Tue Jul 2 15:22:39 2024 -0400

c++: array new with value-initialization [PR115645]

This extends the r11-5179 fix which doesn't work with multidimensional
arrays.  In particular,

  struct S {
explicit S() { }
  };
  auto p = new S[1][1]();

should not say "converting to S from initializer list would use
explicit constructor" because there's no {}.  However, since we
went into the block where we create a {}, we got confused.  We
should not have gotten there but we did because array_p was true.

This patch refines the check once more.

PR c++/115645

gcc/cp/ChangeLog:

* init.cc (build_new): Don't do any deduction for arrays with
bounds if it's value-initialized.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/init.cc| 12 
 gcc/testsuite/g++.dg/expr/anew7.C | 13 +
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 826a31c4a84e..e9561c146d7b 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4005,10 +4005,14 @@ build_new (location_t loc, vec 
**placement, tree type,
   /* P1009: Array size deduction in new-expressions.  */
   const bool array_p = TREE_CODE (type) == ARRAY_TYPE;
   if (*init
-  /* If ARRAY_P, we have to deduce the array bound.  For C++20 paren-init,
-we have to process the parenthesized-list.  But don't do it for (),
-which is value-initialization, and INIT should stay empty.  */
-  && (array_p || (cxx_dialect >= cxx20 && nelts && !(*init)->is_empty (
+  /* If the array didn't specify its bound, we have to deduce it.  */
+  && ((array_p && !TYPE_DOMAIN (type))
+ /* For C++20 array with parenthesized-init, we have to process
+the parenthesized-list.  But don't do it for (), which is
+value-initialization, and INIT should stay empty.  */
+ || (cxx_dialect >= cxx20
+ && (array_p || nelts)
+ && !(*init)->is_empty (
 {
   /* This means we have 'new T[]()'.  */
   if ((*init)->is_empty ())
diff --git a/gcc/testsuite/g++.dg/expr/anew7.C 
b/gcc/testsuite/g++.dg/expr/anew7.C
new file mode 100644
index ..ead5536e1093
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/anew7.C
@@ -0,0 +1,13 @@
+// PR c++/115645
+// { dg-do compile { target c++11 } }
+
+struct S {
+  explicit S() { }
+};
+
+auto p = new S[1][1]();
+auto q = new S[1][1]{}; // { dg-error "explicit" }
+auto r = new S[1]();
+auto s = new S[1]{}; // { dg-error "explicit" }
+auto t = new S[1][1][1]();
+auto u = new S[1][1][1]{}; // { dg-error "explicit" }


[gcc r15-1761] c++: ICE with computed gotos [PR115469]

2024-07-01 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c90e785bb6fde02cc009f296332a1469fcc1261a

commit r15-1761-gc90e785bb6fde02cc009f296332a1469fcc1261a
Author: Marek Polacek 
Date:   Wed Jun 26 17:55:21 2024 -0400

c++: ICE with computed gotos [PR115469]

This is a low-prio crash on invalid code where we ICE on a VAR_DECL
with erroneous type.  I thought I'd try to avoid putting such decls
into ->names and ->names_in_scope but that sounds riskier than the
following cleanup.

PR c++/115469

gcc/cp/ChangeLog:

* decl.cc (automatic_var_with_nontrivial_dtor_p): New.
(poplevel_named_label_1): Use it.
(check_goto_1): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/label17.C: New test.

Diff:
---
 gcc/cp/decl.cc | 20 
 gcc/testsuite/g++.dg/ext/label17.C | 18 ++
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 03deb1493a4..c7457fae7b0 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -514,6 +514,20 @@ level_for_consteval_if (cp_binding_level *b)
  && IF_STMT_CONSTEVAL_P (b->this_entity));
 }
 
+/* True if T is a non-static VAR_DECL that has a non-trivial destructor.
+   See [stmt.dcl]/2.  */
+
+static bool
+automatic_var_with_nontrivial_dtor_p (const_tree t)
+{
+  if (error_operand_p (t))
+return false;
+
+  return (VAR_P (t)
+ && decl_storage_duration (CONST_CAST_TREE (t)) == dk_auto
+ && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (t)));
+}
+
 /* Update data for defined and undefined labels when leaving a scope.  */
 
 int
@@ -575,8 +589,7 @@ poplevel_named_label_1 (named_label_entry **slot, 
cp_binding_level *bl)
if (bl->kind == sk_catch)
  vec_safe_push (cg, get_identifier ("catch"));
for (tree d = use->names_in_scope; d; d = DECL_CHAIN (d))
- if (TREE_CODE (d) == VAR_DECL && !TREE_STATIC (d)
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (d)))
+ if (automatic_var_with_nontrivial_dtor_p (d))
vec_safe_push (cg, d);
  }
 
@@ -4003,8 +4016,7 @@ check_goto_1 (named_label_entry *ent, bool computed)
  tree end = b == level ? names : NULL_TREE;
  for (tree d = b->names; d != end; d = DECL_CHAIN (d))
{
- if (TREE_CODE (d) == VAR_DECL && !TREE_STATIC (d)
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (d)))
+ if (automatic_var_with_nontrivial_dtor_p (d))
{
  if (!identified)
{
diff --git a/gcc/testsuite/g++.dg/ext/label17.C 
b/gcc/testsuite/g++.dg/ext/label17.C
new file mode 100644
index 000..076ef1f798e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/label17.C
@@ -0,0 +1,18 @@
+// PR c++/115469
+// { dg-do compile { target indirect_jumps } }
+// { dg-options "" }
+
+void
+fn1 ()
+{
+  b = &&c;// { dg-error "not declared|not defined" }
+  goto *0;
+}
+
+void
+fn2 ()
+{
+c:
+  b = &&c;  // { dg-error "not declared" }
+  goto *0;
+}


[gcc r15-1760] testsuite: fix spaceship-narrowing1.C

2024-07-01 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:cb39f7df8d1c16cc2763952a9cc0c828ba88b4d7

commit r15-1760-gcb39f7df8d1c16cc2763952a9cc0c828ba88b4d7
Author: Marek Polacek 
Date:   Mon Jul 1 18:12:31 2024 -0400

testsuite: fix spaceship-narrowing1.C

I made sure that Wnarrowing22.C works fine on ILP32, but apparently
I didn't verify that spaceship-narrowing1.C works there as well.  :(

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/spaceship-narrowing1.C: Use __INT64_TYPE__.

Diff:
---
 gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C 
b/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C
index 7769f950bed..9f2ff3ceae4 100644
--- a/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C
@@ -16,7 +16,7 @@ constexpr strong_ordering strong_ordering::greater = 1;
 }
 
 struct A {
-  long i : 48;
+  __INT64_TYPE__ i : 48;
   auto operator <=> (const A&) const = default;
 };


[gcc r15-1759] c++: unresolved overload with comma op [PR115430]

2024-07-01 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c847dcf94499da62e5a28921b404e6e561645d99

commit r15-1759-gc847dcf94499da62e5a28921b404e6e561645d99
Author: Marek Polacek 
Date:   Tue Jun 25 17:42:01 2024 -0400

c++: unresolved overload with comma op [PR115430]

This works:

  template
  int Func(T);
  typedef int (*funcptrtype)(int);
  funcptrtype fp0 = &Func;

but this doesn't:

  funcptrtype fp2 = (0, &Func);

because we only call resolve_nondeduced_context on the LHS (via
convert_to_void) but not on the RHS, so cp_build_compound_expr's
type_unknown_p check issues an error.

PR c++/115430

gcc/cp/ChangeLog:

* typeck.cc (cp_build_compound_expr): Call 
resolve_nondeduced_context
on RHS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept41.C: Remove dg-error.
* g++.dg/overload/addr3.C: New test.

Diff:
---
 gcc/cp/typeck.cc|  4 +++-
 gcc/testsuite/g++.dg/cpp0x/noexcept41.C |  2 +-
 gcc/testsuite/g++.dg/overload/addr3.C   | 24 
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 50f48768a95..55ee867d329 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -8157,6 +8157,8 @@ cp_build_compound_expr (tree lhs, tree rhs, 
tsubst_flags_t complain)
   return rhs;
 }
 
+  rhs = resolve_nondeduced_context (rhs, complain);
+
   if (type_unknown_p (rhs))
 {
   if (complain & tf_error)
@@ -8164,7 +8166,7 @@ cp_build_compound_expr (tree lhs, tree rhs, 
tsubst_flags_t complain)
  "no context to resolve type of %qE", rhs);
   return error_mark_node;
 }
-  
+
   tree ret = build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
   if (eptype)
 ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept41.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept41.C
index 4cd3d8d7854..7c65cebb618 100644
--- a/gcc/testsuite/g++.dg/cpp0x/noexcept41.C
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept41.C
@@ -9,4 +9,4 @@ template  struct a {
 };
 template  auto f(d &&, c &&) -> decltype(declval);
 struct e {};
-static_assert((e{}, declval>),""); // { dg-error "no context to resolve 
type" }
+static_assert((e{}, declval>),"");
diff --git a/gcc/testsuite/g++.dg/overload/addr3.C 
b/gcc/testsuite/g++.dg/overload/addr3.C
new file mode 100644
index 000..b203326de32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/addr3.C
@@ -0,0 +1,24 @@
+// PR c++/115430
+// { dg-do compile }
+
+template
+int Func(T);
+typedef int (*funcptrtype)(int);
+funcptrtype fp0 = &Func;
+funcptrtype fp1 = +&Func;
+funcptrtype fp2 = (0, &Func);
+funcptrtype fp3 = (0, +&Func);
+funcptrtype fp4 = (0, 1, &Func);
+
+template
+void
+g ()
+{
+  funcptrtype fp5 = (0, &Func);
+}
+
+void
+f ()
+{
+  g();
+}


[gcc r15-1758] c++: DR2627, Bit-fields and narrowing conversions [PR94058]

2024-07-01 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:52d71b6b1f0f465a6cf064f61b22fc99453ec132

commit r15-1758-g52d71b6b1f0f465a6cf064f61b22fc99453ec132
Author: Marek Polacek 
Date:   Fri Jun 28 17:51:19 2024 -0400

c++: DR2627, Bit-fields and narrowing conversions [PR94058]

This DR (https://cplusplus.github.io/CWG/issues/2627.html) says that
even if we are converting from an integer type or unscoped enumeration type
to an integer type that cannot represent all the values of the original
type, it's not narrowing if "the source is a bit-field whose width w is
less than that of its type (or, for an enumeration type, its underlying
type) and the target type can represent all the values of a hypothetical
extended integer type with width w and with the same signedness as the
original type".

DR 2627
PR c++/94058
PR c++/104392

gcc/cp/ChangeLog:

* typeck2.cc (check_narrowing): Don't warn if the conversion isn't
narrowing as per DR 2627.

gcc/testsuite/ChangeLog:

* g++.dg/DRs/dr2627.C: New test.
* g++.dg/cpp0x/Wnarrowing22.C: New test.
* g++.dg/cpp2a/spaceship-narrowing1.C: New test.
* g++.dg/cpp2a/spaceship-narrowing2.C: New test.

Diff:
---
 gcc/cp/typeck2.cc | 12 ++
 gcc/testsuite/g++.dg/DRs/dr2627.C | 13 ++
 gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C | 49 +++
 gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C | 34 
 gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing2.C | 26 
 5 files changed, 134 insertions(+)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 7782f38da43..30a6fbe95c9 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1012,6 +1012,18 @@ check_narrowing (tree type, tree init, tsubst_flags_t 
complain,
   if (TREE_CODE (ftype) == ENUMERAL_TYPE)
/* Check for narrowing based on the values of the enumeration. */
ftype = ENUM_UNDERLYING_TYPE (ftype);
+  /* Undo convert_bitfield_to_declared_type (STRIP_NOPS isn't enough).  */
+  tree op = init;
+  while (CONVERT_EXPR_P (op))
+   op = TREE_OPERAND (op, 0);
+  /* Core 2627 says that we shouldn't warn when "the source is a bit-field
+whose width w is less than that of its type (or, for an enumeration
+type, its underlying type) and the target type can represent all the
+values of a hypothetical extended integer type with width w and with
+the same signedness as the original type".  */
+  if (is_bitfield_expr_with_lowered_type (op)
+ && TYPE_PRECISION (TREE_TYPE (op)) < TYPE_PRECISION (ftype))
+   ftype = TREE_TYPE (op);
   if ((tree_int_cst_lt (TYPE_MAX_VALUE (type),
TYPE_MAX_VALUE (ftype))
   || tree_int_cst_lt (TYPE_MIN_VALUE (ftype),
diff --git a/gcc/testsuite/g++.dg/DRs/dr2627.C 
b/gcc/testsuite/g++.dg/DRs/dr2627.C
new file mode 100644
index 000..fe7f28613ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2627.C
@@ -0,0 +1,13 @@
+// DR 2627 - Bit-fields and narrowing conversions
+// { dg-do compile { target c++20 } }
+
+#include 
+
+struct C {
+  long long i : 8;
+};
+
+void f() {
+  C x{1}, y{2};
+  x.i <=> y.i;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C 
b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C
new file mode 100644
index 000..dd30451a7cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C
@@ -0,0 +1,49 @@
+// DR 2627 - Bit-fields and narrowing conversions
+// PR c++/94058
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-error=narrowing" }
+
+using int64_t = __INT64_TYPE__;
+using int32_t = __INT32_TYPE__;
+
+struct A {
+  int64_t i1 : __CHAR_BIT__;
+  int64_t i2 : sizeof (int32_t) * __CHAR_BIT__ - 1;
+  int64_t i3 : sizeof (int32_t) * __CHAR_BIT__;
+  int64_t i4 : sizeof (int32_t) * __CHAR_BIT__ + 1;
+  int64_t i5 : sizeof (int64_t) * __CHAR_BIT__ - 1;
+  int64_t i6 : sizeof (int64_t) * __CHAR_BIT__;
+} a;
+
+int32_t i1{a.i1};
+int32_t i2{a.i2};
+int32_t i3{a.i3};
+int32_t i4{a.i4}; // { dg-warning "narrowing conversion" }
+int32_t i5{a.i5}; // { dg-warning "narrowing conversion" }
+int32_t i6{a.i6}; // { dg-warning "narrowing conversion" }
+
+struct B {
+  bool b1 : sizeof (bool) * __CHAR_BIT__;
+  bool b2 : sizeof (bool);
+} b;
+
+signed char b1{b.b1};
+signed char b2{b.b2};
+
+enum E : int64_t { E1 };
+
+struct C {
+  E e1 : __CHAR_BIT__;
+  E e2 : sizeof (int32_t) * __CHAR_BIT__ - 1;
+  E e3 : sizeof (int32_t) * __CHAR_BIT__;
+  E e4 : sizeof (int32_t) * __CHAR_BIT__ + 1;
+  E e5 : sizeof (int64_t) * __CHAR_BIT__ - 1;
+  E e6 : sizeof (int64_t) * __CHAR_BIT__;
+} c;
+
+int32_t e1{c.e1};
+int32_t e2{c.e2};
+int32_t e3{c.e3};
+int32_t e4{c.e4}; // { dg-warning "narrowing conversion" }
+int32_t e5{c.e5}; // { dg-warning "narrowing conversion" }
+int32_t e6{c.e6}; // { dg-warning "narrowing conversion

[gcc r15-1625] c++: ICE with __has_unique_object_representations [PR115476]

2024-06-25 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:fc382a373e6824bb998007d1dcb0805b0cf4b8e8

commit r15-1625-gfc382a373e6824bb998007d1dcb0805b0cf4b8e8
Author: Marek Polacek 
Date:   Mon Jun 17 17:53:12 2024 -0400

c++: ICE with __has_unique_object_representations [PR115476]

Here we started to ICE with r13-25: in check_trait_type, for "X[]" we
return true here:

  if (kind == 1 && TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
return true; // Array of unknown bound. Don't care about completeness.

and then end up crashing in record_has_unique_obj_representations:

4836  if (cur != wi::to_offset (sz))

because sz is null.


https://eel.is/c++draft/type.traits#tab:meta.unary.prop-row-47-column-3-sentence-1
says that the preconditions for __has_unique_object_representations are:
"T shall be a complete type, cv void, or an array of unknown bound" and
that "For an array type T, the same result as
has_unique_object_representations_v>" so T[]
should be treated as T.  So we should use kind==2 for the trait.

PR c++/115476

gcc/cp/ChangeLog:

* semantics.cc (finish_trait_expr)
: Move below to call
check_trait_type with kind==2.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/has-unique-obj-representations4.C: New test.

Diff:
---
 gcc/cp/semantics.cc  |  2 +-
 .../g++.dg/cpp1z/has-unique-obj-representations4.C   | 16 
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c1813d37c6..8e3e4e23b72 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12959,7 +12959,6 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, 
tree type1, tree type2)
 case CPTK_HAS_NOTHROW_COPY:
 case CPTK_HAS_TRIVIAL_COPY:
 case CPTK_HAS_TRIVIAL_DESTRUCTOR:
-case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
   if (!check_trait_type (type1))
return error_mark_node;
   break;
@@ -12969,6 +12968,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, 
tree type1, tree type2)
 case CPTK_IS_STD_LAYOUT:
 case CPTK_IS_TRIVIAL:
 case CPTK_IS_TRIVIALLY_COPYABLE:
+case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
   if (!check_trait_type (type1, /* kind = */ 2))
return error_mark_node;
   break;
diff --git a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations4.C 
b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations4.C
new file mode 100644
index 000..d6949dc7005
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations4.C
@@ -0,0 +1,16 @@
+// PR c++/115476
+// { dg-do compile { target c++11 } }
+
+struct X;
+static_assert(__has_unique_object_representations(X), "");   // { dg-error 
"invalid use of incomplete type" }
+static_assert(__has_unique_object_representations(X[]), "");  // { dg-error 
"invalid use of incomplete type" }
+static_assert(__has_unique_object_representations(X[1]), "");  // { dg-error 
"invalid use of incomplete type" }
+static_assert(__has_unique_object_representations(X[][1]), "");  // { dg-error 
"invalid use of incomplete type" }
+
+struct X {
+  int x;
+};
+static_assert(__has_unique_object_representations(X), "");
+static_assert(__has_unique_object_representations(X[]), "");
+static_assert(__has_unique_object_representations(X[1]), "");
+static_assert(__has_unique_object_representations(X[][1]), "");


[gcc r15-1621] c++: ICE with generic lambda and pack expansion [PR115425]

2024-06-25 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:ed6ffc4e62f716d1b31d599d22594dd969da137f

commit r15-1621-ged6ffc4e62f716d1b31d599d22594dd969da137f
Author: Marek Polacek 
Date:   Fri Jun 14 17:50:29 2024 -0400

c++: ICE with generic lambda and pack expansion [PR115425]

In r13-272 we hardened the *_PACK_EXPANSION and *_ARGUMENT_PACK macros.
That trips up here because make_pack_expansion returns error_mark_node
and we access that with PACK_EXPANSION_LOCAL_P.

PR c++/115425

gcc/cp/ChangeLog:

* pt.cc (tsubst_pack_expansion): Return error_mark_node if
make_pack_expansion doesn't work out.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-generic12.C: New test.

Diff:
---
 gcc/cp/pt.cc  |  2 ++
 gcc/testsuite/g++.dg/cpp2a/lambda-generic12.C | 25 +
 2 files changed, 27 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index daa8ac386dc..017cc7fd0ab 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13775,6 +13775,8 @@ tsubst_pack_expansion (tree t, tree args, 
tsubst_flags_t complain,
   else
result = tsubst (pattern, args, complain, in_decl);
   result = make_pack_expansion (result, complain);
+  if (result == error_mark_node)
+   return error_mark_node;
   PACK_EXPANSION_LOCAL_P (result) = PACK_EXPANSION_LOCAL_P (t);
   PACK_EXPANSION_SIZEOF_P (result) = PACK_EXPANSION_SIZEOF_P (t);
   if (PACK_EXPANSION_AUTO_P (t))
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-generic12.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-generic12.C
new file mode 100644
index 000..219529c7c32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-generic12.C
@@ -0,0 +1,25 @@
+// PR c++/115425
+// { dg-do compile { target c++20 } }
+
+using size_t = decltype(sizeof(0));
+
+template 
+struct X {};
+
+template
+void foo(X);
+
+template
+struct S;
+
+template
+auto test() {
+  constexpr static auto x = foo>(); // { dg-error "no 
matching function" }
+  return [](X) {
+(typename S::type{}, ...);
+  }(X<__integer_pack (0)...>{});
+}
+
+int main() {
+  test();
+}


[gcc r15-1620] c++: ICE with __dynamic_cast redecl [PR115501]

2024-06-25 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:71f484d02b2b3e8616cd7af27a0d4c72e4c7e977

commit r15-1620-g71f484d02b2b3e8616cd7af27a0d4c72e4c7e977
Author: Marek Polacek 
Date:   Tue Jun 18 10:50:49 2024 -0400

c++: ICE with __dynamic_cast redecl [PR115501]

Since r13-3299, build_dynamic_cast_1 calls pushdecl which calls
duplicate_decls and that in this testcase emits the "conflicting
declaration" error and returns error_mark_node, so the subsequent
build_cxx_call crashes on the error_mark_node.

PR c++/115501

gcc/cp/ChangeLog:

* rtti.cc (build_dynamic_cast_1): Return if dcast_fn is erroneous.

gcc/testsuite/ChangeLog:

* g++.dg/rtti/dyncast8.C: New test.

Diff:
---
 gcc/cp/rtti.cc   |  2 ++
 gcc/testsuite/g++.dg/rtti/dyncast8.C | 15 +++
 2 files changed, 17 insertions(+)

diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc
index ed69606f4dd..cc006ea927f 100644
--- a/gcc/cp/rtti.cc
+++ b/gcc/cp/rtti.cc
@@ -794,6 +794,8 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
  pop_abi_namespace (flags);
  dynamic_cast_node = dcast_fn;
}
+ if (dcast_fn == error_mark_node)
+   return error_mark_node;
  result = build_cxx_call (dcast_fn, 4, elems, complain);
  SET_EXPR_LOCATION (result, loc);
 
diff --git a/gcc/testsuite/g++.dg/rtti/dyncast8.C 
b/gcc/testsuite/g++.dg/rtti/dyncast8.C
new file mode 100644
index 000..de23433dd9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/rtti/dyncast8.C
@@ -0,0 +1,15 @@
+// PR c++/115501
+// { dg-do compile }
+
+struct s{virtual void f();};
+struct s1 : s{};
+namespace __cxxabiv1
+{
+  extern "C" void __dynamic_cast(); // { dg-message "previous declaration" }
+}
+void diagnostic_information_impl(s const *se)
+{
+  dynamic_cast(se);
+}
+
+// { dg-error "conflicting declaration" "" { target *-*-* } 0 }


[gcc r15-871] c++: extend -Wself-move for mem-init-list [PR109396]

2024-05-28 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:efaaae49b307fcc7e771518da3edae49f92c19db

commit r15-871-gefaaae49b307fcc7e771518da3edae49f92c19db
Author: Marek Polacek 
Date:   Thu May 23 15:49:42 2024 -0400

c++: extend -Wself-move for mem-init-list [PR109396]

We already warn for:

  x = std::move (x);

which triggers:

  warning: moving 'x' of type 'int' to itself [-Wself-move]

but bug 109396 reports that this doesn't work for a member-initializer-list:

  X() : x(std::move (x))

so this patch amends that.

PR c++/109396

gcc/cp/ChangeLog:

* cp-tree.h (maybe_warn_self_move): Declare.
* init.cc (perform_member_init): Call maybe_warn_self_move.
* typeck.cc (maybe_warn_self_move): No longer static.  Change the
return type to bool.  Also warn when called from
a member-initializer-list.  Drop the inform call.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wself-move2.C: New test.

Diff:
---
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/init.cc  |  5 +++--
 gcc/cp/typeck.cc| 32 +++-
 gcc/testsuite/g++.dg/warn/Wself-move2.C | 37 +
 4 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 655850a9ab6..6206482c602 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8263,6 +8263,7 @@ extern cp_expr build_c_cast   
(location_t loc, tree type,
 cp_expr expr);
 extern tree cp_build_c_cast(location_t, tree, tree,
 tsubst_flags_t);
+extern bool maybe_warn_self_move   (location_t, tree, tree);
 extern cp_expr build_x_modify_expr (location_t, tree,
 enum tree_code, tree,
 tree, tsubst_flags_t);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 52396d87a8c..4a7ed7f5302 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -999,7 +999,7 @@ perform_member_init (tree member, tree init, hash_set 
&uninitialized)
   if (decl == error_mark_node)
 return;
 
-  if ((warn_init_self || warn_uninitialized)
+  if ((warn_init_self || warn_uninitialized || warn_self_move)
   && init
   && TREE_CODE (init) == TREE_LIST
   && TREE_CHAIN (init) == NULL_TREE)
@@ -1013,7 +1013,8 @@ perform_member_init (tree member, tree init, 
hash_set &uninitialized)
warning_at (DECL_SOURCE_LOCATION (current_function_decl),
OPT_Winit_self, "%qD is initialized with itself",
member);
-  else
+  else if (!maybe_warn_self_move (input_location, member,
+ TREE_VALUE (init)))
find_uninit_fields (&val, &uninitialized, decl);
 }
 
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 4a153a8baf9..1b7a31d32f3 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9355,27 +9355,27 @@ cp_build_c_cast (location_t loc, tree type, tree expr,
 
 /* Warn when a value is moved to itself with std::move.  LHS is the target,
RHS may be the std::move call, and LOC is the location of the whole
-   assignment.  */
+   assignment.  Return true if we warned.  */
 
-static void
+bool
 maybe_warn_self_move (location_t loc, tree lhs, tree rhs)
 {
   if (!warn_self_move)
-return;
+return false;
 
   /* C++98 doesn't know move.  */
   if (cxx_dialect < cxx11)
-return;
+return false;
 
   if (processing_template_decl)
-return;
+return false;
 
   if (!REFERENCE_REF_P (rhs)
   || TREE_CODE (TREE_OPERAND (rhs, 0)) != CALL_EXPR)
-return;
+return false;
   tree fn = TREE_OPERAND (rhs, 0);
   if (!is_std_move_p (fn))
-return;
+return false;
 
   /* Just a little helper to strip * and various NOPs.  */
   auto extract_op = [] (tree &op) {
@@ -9393,13 +9393,17 @@ maybe_warn_self_move (location_t loc, tree lhs, tree 
rhs)
   tree type = TREE_TYPE (lhs);
   tree orig_lhs = lhs;
   extract_op (lhs);
-  if (cp_tree_equal (lhs, arg))
-{
-  auto_diagnostic_group d;
-  if (warning_at (loc, OPT_Wself_move,
- "moving %qE of type %qT to itself", orig_lhs, type))
-   inform (loc, "remove % call");
-}
+  if (cp_tree_equal (lhs, arg)
+  /* Also warn in a member-initializer-list, as in : i(std::move(i)).  */
+  || (TREE_CODE (lhs) == FIELD_DECL
+ && TREE_CODE (arg) == COMPONENT_REF
+ && cp_tree_equal (TREE_OPERAND (arg, 0), current_class_ref)
+ && TREE_OPERAND (arg, 1) == lhs))
+if (warning_at (loc, OPT_Wself_move,
+   "moving %qE of type %qT to itself", orig_lhs, type))
+  return true;
+
+  return false;
 }
 
 /* For use from the C common bits.  */
diff --git a/gcc/testsuite/g++.dg/warn/W

[gcc r15-868] c++: mark TARGET_EXPRs for function arguments eliding [PR114707]

2024-05-28 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:5bc731b83b51910dc7f7cacddb4257a16d62ee38

commit r15-868-g5bc731b83b51910dc7f7cacddb4257a16d62ee38
Author: Marek Polacek 
Date:   Wed May 22 16:28:02 2024 -0400

c++: mark TARGET_EXPRs for function arguments eliding [PR114707]

Coming back to our discussion in
:
TARGET_EXPRs that initialize a function argument are not marked
TARGET_EXPR_ELIDING_P even though gimplify_arg drops such TARGET_EXPRs
on the floor.  To work around it, I added a pset to
replace_placeholders_for_class_temp_r, but it would be best to just rely
on TARGET_EXPR_ELIDING_P.

PR c++/114707

gcc/cp/ChangeLog:

* call.cc (convert_for_arg_passing): Call set_target_expr_eliding.
* typeck2.cc (replace_placeholders_for_class_temp_r): Don't use 
pset.
(digest_nsdmi_init): Call cp_walk_tree_without_duplicates instead of
cp_walk_tree.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/call.cc|  4 
 gcc/cp/typeck2.cc | 20 
 2 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 886760af699..85536fc25ff 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9437,6 +9437,10 @@ convert_for_arg_passing (tree type, tree val, 
tsubst_flags_t complain)
   if (complain & tf_warning)
 warn_for_address_of_packed_member (type, val);
 
+  /* gimplify_arg elides TARGET_EXPRs that initialize a function argument.  */
+  if (SIMPLE_TARGET_EXPR_P (val))
+set_target_expr_eliding (val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 06bad4d3303..7782f38da43 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1409,16 +1409,14 @@ digest_init_flags (tree type, tree init, int flags, 
tsubst_flags_t complain)
in the context of guaranteed copy elision).  */
 
 static tree
-replace_placeholders_for_class_temp_r (tree *tp, int *, void *data)
+replace_placeholders_for_class_temp_r (tree *tp, int *, void *)
 {
   tree t = *tp;
-  auto pset = static_cast *>(data);
 
   /* We're looking for a TARGET_EXPR nested in the whole expression.  */
   if (TREE_CODE (t) == TARGET_EXPR
   /* That serves as temporary materialization, not an initializer.  */
-  && !TARGET_EXPR_ELIDING_P (t)
-  && !pset->add (t))
+  && !TARGET_EXPR_ELIDING_P (t))
 {
   tree init = TARGET_EXPR_INITIAL (t);
   while (TREE_CODE (init) == COMPOUND_EXPR)
@@ -1433,16 +1431,6 @@ replace_placeholders_for_class_temp_r (tree *tp, int *, 
void *data)
  gcc_checking_assert (!find_placeholders (init));
}
 }
-  /* TARGET_EXPRs initializing function arguments are not marked as eliding,
- even though gimplify_arg drops them on the floor.  Don't go replacing
- placeholders in them.  */
-  else if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
-for (int i = 0; i < call_expr_nargs (t); ++i)
-  {
-   tree arg = get_nth_callarg (t, i);
-   if (TREE_CODE (arg) == TARGET_EXPR && !TARGET_EXPR_ELIDING_P (arg))
- pset->add (arg);
-  }
 
   return NULL_TREE;
 }
@@ -1490,8 +1478,8 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t 
complain)
  temporary materialization does not occur when initializing an object
  from a prvalue of the same type, therefore we must not replace the
  placeholder with a temporary object so that it can be elided.  */
-  hash_set pset;
-  cp_walk_tree (&init, replace_placeholders_for_class_temp_r, &pset, nullptr);
+  cp_walk_tree_without_duplicates (&init, 
replace_placeholders_for_class_temp_r,
+  nullptr);
 
   return init;
 }


[gcc r14-10235] c++: failure to suppress -Wsizeof-array-div in template [PR114983]

2024-05-22 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c27d6c7fd03f95483d372eae2c96912ceee98a5e

commit r14-10235-gc27d6c7fd03f95483d372eae2c96912ceee98a5e
Author: Marek Polacek 
Date:   Wed May 8 17:02:49 2024 -0400

c++: failure to suppress -Wsizeof-array-div in template [PR114983]

-Wsizeof-array-div offers a way to suppress the warning by wrapping
the second operand of the division in parens:

  sizeof (samplesBuffer) / (sizeof(unsigned char))

but this doesn't work in a template, because we fail to propagate
the suppression bits.  Do it, then.

The finish_parenthesized_expr hunk is not needed because suppress_warning
isn't very fine-grained.  But I think it makes sense to be explicit and
not rely on OPT_Wparentheses also suppressing OPT_Wsizeof_array_div.

PR c++/114983

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Use copy_warning.
* semantics.cc (finish_parenthesized_expr): Also suppress
-Wsizeof-array-div.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wsizeof-array-div3.C: New test.

(cherry picked from commit 646db3d30bd071a1b671b4f91c9ea2ab7f2be21c)

Diff:
---
 gcc/cp/pt.cc   |  1 +
 gcc/cp/semantics.cc|  2 ++
 gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C | 27 ++
 3 files changed, 30 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ba47620ec59..6b54e6b10fc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20576,6 +20576,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
TREE_READONLY (r) = 1;
  }
SET_EXPR_LOCATION (r, EXPR_LOCATION (t));
+   copy_warning (r, t);
  }
RETURN (r);
   }
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 02c7c1bf5a4..4eeec209fa4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2306,6 +2306,8 @@ finish_parenthesized_expr (cp_expr expr)
   /* This inhibits warnings in maybe_warn_unparenthesized_assignment
 and c_common_truthvalue_conversion.  */
   suppress_warning (STRIP_REFERENCE_REF (*expr), OPT_Wparentheses);
+  /* And maybe_warn_sizeof_array_div.  */
+  suppress_warning (STRIP_REFERENCE_REF (*expr), OPT_Wsizeof_array_div);
 }
 
   if (TREE_CODE (expr) == OFFSET_REF
diff --git a/gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C 
b/gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C
new file mode 100644
index 000..bfd690325e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C
@@ -0,0 +1,27 @@
+// PR c++/114983
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wsizeof-array-div" }
+
+using size_t = decltype (sizeof (0));
+unsigned int samplesBuffer[40];
+
+template 
+constexpr inline size_t fn1()
+{
+  return ((sizeof(samplesBuffer)) / (sizeof(T))); // { dg-bogus "expression 
does not compute" }
+}
+
+template 
+constexpr inline size_t fn2()
+{
+  return ((sizeof(samplesBuffer)) / sizeof(T)); // { dg-warning "expression 
does not compute" }
+}
+
+size_t
+g ()
+{
+  auto sz = sizeof (samplesBuffer) / (sizeof(unsigned char));
+  sz += fn1();
+  sz += fn2(); // { dg-message "required from here" }
+  return sz;
+}


[gcc r15-523] c++: ICE with reference NSDMI [PR114854]

2024-05-15 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:1a05332bbac98a4c002bef3fb45a3ad9d56b3a71

commit r15-523-g1a05332bbac98a4c002bef3fb45a3ad9d56b3a71
Author: Marek Polacek 
Date:   Wed May 8 15:43:58 2024 -0400

c++: ICE with reference NSDMI [PR114854]

Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:

  /* A TARGET_EXPR that expresses direct-initialization should have been
 elided by cp_gimplify_init_expr.  */
  gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));

the TARGET_EXPR in question is created for the NSDMI in:

  class Vector { int m_size; };
  struct S {
const Vector &vec{};
  };

where we first need to create a Vector{} temporary, and then bind the
vec reference to it.  The temporary is represented by a TARGET_EXPR
and it cannot be elided.  When we create an object of type S, we get

  D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR }

where the TARGET_EXPR is no longer direct-initializing anything.

Fixed by not setting TARGET_EXPR_DIRECT_INIT_P in 
convert_like_internal/ck_user.

PR c++/114854

gcc/cp/ChangeLog:

* call.cc (convert_like_internal) : Don't set
TARGET_EXPR_DIRECT_INIT_P.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/nsdmi-aggr22.C: New test.

Diff:
---
 gcc/cp/call.cc|  6 +-
 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C | 12 
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index e058da7735fa..ed68eb3c5684 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -8597,16 +8597,12 @@ convert_like_internal (conversion *convs, tree expr, 
tree fn, int argnum,
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (totype)
&& !processing_template_decl)
  {
-   bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
if (abstract_virtuals_error (NULL_TREE, totype, complain))
  return error_mark_node;
expr = build_value_init (totype, complain);
expr = get_target_expr (expr, complain);
if (expr != error_mark_node)
- {
-   TARGET_EXPR_LIST_INIT_P (expr) = true;
-   TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
- }
+ TARGET_EXPR_LIST_INIT_P (expr) = true;
return expr;
  }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C 
b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
new file mode 100644
index ..a4f9ae19ca9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
@@ -0,0 +1,12 @@
+// PR c++/114854
+// { dg-do compile { target c++14 } }
+
+struct Vector {
+  int m_size;
+};
+struct S {
+  const Vector &vec{};
+};
+
+void spawn(S);
+void test() { spawn({}); }


[gcc r15-522] c++: DR 569, DR 1693: fun with semicolons [PR113760]

2024-05-15 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:0b3eac4b54a52bf206b88743d1e987badc97cff4

commit r15-522-g0b3eac4b54a52bf206b88743d1e987badc97cff4
Author: Marek Polacek 
Date:   Mon Feb 12 19:36:16 2024 -0500

c++: DR 569, DR 1693: fun with semicolons [PR113760]

Prompted by c++/113760, I started looking into a bogus "extra ;"
warning in C++11.  It quickly turned out that if I want to fix
this for good, the fix will not be so small.

This patch touches on DR 569, an extra ; at namespace scope should
be allowed since C++11:

  struct S {
  };
  ; // pedwarn in C++98

It also touches on DR 1693, which allows superfluous semicolons in
class definitions since C++11:

  struct S {
int a;
; // pedwarn in C++98
  };

Note that a single semicolon is valid after a member function definition:

  struct S {
void foo () {}; // only warns with -Wextra-semi
  };

There's a new function maybe_warn_extra_semi to handle all of the above
in a single place.  So now they all get a fix-it hint.

-Wextra-semi turns on all "extra ;" diagnostics.  Currently, options
like -Wc++11-compat or -Wc++11-extensions are not considered.

DR 1693
PR c++/113760
DR 569

gcc/c-family/ChangeLog:

* c.opt (Wextra-semi): Initialize to -1.

gcc/cp/ChangeLog:

* parser.cc (extra_semi_kind): New.
(maybe_warn_extra_semi): New.
(cp_parser_declaration): Call maybe_warn_extra_semi.
(cp_parser_member_declaration): Likewise.

gcc/ChangeLog:

* doc/invoke.texi: Update -Wextra-semi documentation.

gcc/testsuite/ChangeLog:

* g++.dg/diagnostic/semicolon1.C: New test.
* g++.dg/diagnostic/semicolon10.C: New test.
* g++.dg/diagnostic/semicolon11.C: New test.
* g++.dg/diagnostic/semicolon12.C: New test.
* g++.dg/diagnostic/semicolon13.C: New test.
* g++.dg/diagnostic/semicolon14.C: New test.
* g++.dg/diagnostic/semicolon15.C: New test.
* g++.dg/diagnostic/semicolon16.C: New test.
* g++.dg/diagnostic/semicolon17.C: New test.
* g++.dg/diagnostic/semicolon2.C: New test.
* g++.dg/diagnostic/semicolon3.C: New test.
* g++.dg/diagnostic/semicolon4.C: New test.
* g++.dg/diagnostic/semicolon5.C: New test.
* g++.dg/diagnostic/semicolon6.C: New test.
* g++.dg/diagnostic/semicolon7.C: New test.
* g++.dg/diagnostic/semicolon8.C: New test.
* g++.dg/diagnostic/semicolon9.C: New test.

Diff:
---
 gcc/c-family/c.opt|  2 +-
 gcc/cp/parser.cc  | 92 ++-
 gcc/doc/invoke.texi   | 29 -
 gcc/testsuite/g++.dg/diagnostic/semicolon1.C  | 18 ++
 gcc/testsuite/g++.dg/diagnostic/semicolon10.C | 11 
 gcc/testsuite/g++.dg/diagnostic/semicolon11.C | 29 +
 gcc/testsuite/g++.dg/diagnostic/semicolon12.C | 29 +
 gcc/testsuite/g++.dg/diagnostic/semicolon13.C | 29 +
 gcc/testsuite/g++.dg/diagnostic/semicolon14.C | 29 +
 gcc/testsuite/g++.dg/diagnostic/semicolon15.C | 29 +
 gcc/testsuite/g++.dg/diagnostic/semicolon16.C | 38 +++
 gcc/testsuite/g++.dg/diagnostic/semicolon17.C | 29 +
 gcc/testsuite/g++.dg/diagnostic/semicolon2.C  | 18 ++
 gcc/testsuite/g++.dg/diagnostic/semicolon3.C  | 18 ++
 gcc/testsuite/g++.dg/diagnostic/semicolon4.C  | 18 ++
 gcc/testsuite/g++.dg/diagnostic/semicolon5.C  | 18 ++
 gcc/testsuite/g++.dg/diagnostic/semicolon6.C  | 23 +++
 gcc/testsuite/g++.dg/diagnostic/semicolon7.C  | 18 ++
 gcc/testsuite/g++.dg/diagnostic/semicolon8.C  | 11 
 gcc/testsuite/g++.dg/diagnostic/semicolon9.C  | 11 
 20 files changed, 480 insertions(+), 19 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 403abc1f26e1..fb34c3b70319 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -727,7 +727,7 @@ C ObjC C++ ObjC++ Warning
 ; in common.opt
 
 Wextra-semi
-C++ ObjC++ Var(warn_extra_semi) Warning
+C++ ObjC++ Var(warn_extra_semi) Init(-1) Warning
 Warn about semicolon after in-class function definition.
 
 Wflex-array-member-not-at-end
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 7306ce9a8a8b..476ddc0d63ad 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -15331,6 +15331,61 @@ cp_parser_module_export (cp_parser *parser)
   module_kind = mk;
 }
 
+/* Used for maybe_warn_extra_semi.  */
+
+enum class extra_semi_kind { decl, member, in_class_fn_def };
+
+/* Warn about an extra semicolon.  KIND says in which context the extra
+   semicolon occurs.  */
+
+static void
+maybe_warn_extra_semi (location_t loc, extra_semi_kind kind)
+{
+  /* -Wno-extra-semi suppresses all.  */
+  if (warn_extra_semi 

[gcc r15-515] c++: add test for DR 2855

2024-05-15 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:3cefe91b74f65f0db71472e01ca83c69e2cd81cc

commit r15-515-g3cefe91b74f65f0db71472e01ca83c69e2cd81cc
Author: Marek Polacek 
Date:   Tue May 14 13:48:30 2024 -0400

c++: add test for DR 2855

Let

  int8_t x = 127;

This DR says that while

  x++;

invokes UB,

  ++x;

does not.  The resolution was to make the first one valid.  The
following test verifies that we don't report any errors in a constexpr
context.

DR 2855

gcc/testsuite/ChangeLog:

* g++.dg/DRs/dr2855.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/DRs/dr2855.C | 16 
 1 file changed, 16 insertions(+)

diff --git a/gcc/testsuite/g++.dg/DRs/dr2855.C 
b/gcc/testsuite/g++.dg/DRs/dr2855.C
new file mode 100644
index ..b4609ceaa158
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2855.C
@@ -0,0 +1,16 @@
+// DR 2855, Undefined behavior in postfix increment
+// { dg-do compile { target c++14 } }
+
+using int8_t = signed char;
+
+constexpr int
+f ()
+{
+  int8_t x = 127;
+  x++;
+  int8_t z = 127;
+  ++z;
+  return x + z;
+}
+
+constexpr int i = f();


[gcc r15-351] c++: failure to suppress -Wsizeof-array-div in template [PR114983]

2024-05-09 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:646db3d30bd071a1b671b4f91c9ea2ab7f2be21c

commit r15-351-g646db3d30bd071a1b671b4f91c9ea2ab7f2be21c
Author: Marek Polacek 
Date:   Wed May 8 17:02:49 2024 -0400

c++: failure to suppress -Wsizeof-array-div in template [PR114983]

-Wsizeof-array-div offers a way to suppress the warning by wrapping
the second operand of the division in parens:

  sizeof (samplesBuffer) / (sizeof(unsigned char))

but this doesn't work in a template, because we fail to propagate
the suppression bits.  Do it, then.

The finish_parenthesized_expr hunk is not needed because suppress_warning
isn't very fine-grained.  But I think it makes sense to be explicit and
not rely on OPT_Wparentheses also suppressing OPT_Wsizeof_array_div.

PR c++/114983

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Use copy_warning.
* semantics.cc (finish_parenthesized_expr): Also suppress
-Wsizeof-array-div.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wsizeof-array-div3.C: New test.

Diff:
---
 gcc/cp/pt.cc   |  1 +
 gcc/cp/semantics.cc|  2 ++
 gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C | 27 ++
 3 files changed, 30 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8787eabb9fdb..a7d9fcf930e2 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20570,6 +20570,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
TREE_READONLY (r) = 1;
  }
SET_EXPR_LOCATION (r, EXPR_LOCATION (t));
+   copy_warning (r, t);
  }
RETURN (r);
   }
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b8c2bf8771fc..71520dcd4fa9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2306,6 +2306,8 @@ finish_parenthesized_expr (cp_expr expr)
   /* This inhibits warnings in maybe_warn_unparenthesized_assignment
 and c_common_truthvalue_conversion.  */
   suppress_warning (STRIP_REFERENCE_REF (*expr), OPT_Wparentheses);
+  /* And maybe_warn_sizeof_array_div.  */
+  suppress_warning (STRIP_REFERENCE_REF (*expr), OPT_Wsizeof_array_div);
 }
 
   if (TREE_CODE (expr) == OFFSET_REF
diff --git a/gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C 
b/gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C
new file mode 100644
index ..bfd690325e51
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C
@@ -0,0 +1,27 @@
+// PR c++/114983
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wsizeof-array-div" }
+
+using size_t = decltype (sizeof (0));
+unsigned int samplesBuffer[40];
+
+template 
+constexpr inline size_t fn1()
+{
+  return ((sizeof(samplesBuffer)) / (sizeof(T))); // { dg-bogus "expression 
does not compute" }
+}
+
+template 
+constexpr inline size_t fn2()
+{
+  return ((sizeof(samplesBuffer)) / sizeof(T)); // { dg-warning "expression 
does not compute" }
+}
+
+size_t
+g ()
+{
+  auto sz = sizeof (samplesBuffer) / (sizeof(unsigned char));
+  sz += fn1();
+  sz += fn2(); // { dg-message "required from here" }
+  return sz;
+}


[gcc r15-348] c++: lambda capturing structured bindings [PR85889]

2024-05-09 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:46bafd9a6b9b776142e0b1424a6ac02e3a2fd300

commit r15-348-g46bafd9a6b9b776142e0b1424a6ac02e3a2fd300
Author: Marek Polacek 
Date:   Fri Mar 1 17:13:02 2024 -0500

c++: lambda capturing structured bindings [PR85889]

 clarifies that it's OK to capture structured
bindings.

[expr.prim.lambda.capture]/4 says "The identifier in a simple-capture shall
denote a local entity" and [basic.pre]/3: "An entity is a [...] structured
binding".

It doesn't appear that this was made a DR, so, strictly speaking, we
should have a -Wc++20-extensions warning, like clang++.

PR c++/85889

gcc/cp/ChangeLog:

* lambda.cc (add_capture): Add a pedwarn for capturing structured
bindings.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/decomp3.C: Use -Wno-c++20-extensions.
* g++.dg/cpp1z/decomp60.C: New test.

Diff:
---
 gcc/cp/lambda.cc  | 10 ++
 gcc/testsuite/g++.dg/cpp1z/decomp60.C | 12 
 gcc/testsuite/g++.dg/cpp2a/decomp3.C  |  2 +-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 4b1f9391fee1..630cc4eade14 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -607,6 +607,16 @@ add_capture (tree lambda, tree id, tree orig_init, bool 
by_reference_p,
 TCTX_CAPTURE_BY_COPY, type))
return error_mark_node;
}
+
+  if (cxx_dialect < cxx20)
+   {
+ auto_diagnostic_group d;
+ tree stripped_init = tree_strip_any_location_wrapper (initializer);
+ if (DECL_DECOMPOSITION_P (stripped_init)
+ && pedwarn (input_location, OPT_Wc__20_extensions,
+ "captured structured bindings are a C++20 extension"))
+   inform (DECL_SOURCE_LOCATION (stripped_init), "declared here");
+   }
 }
 
   /* Add __ to the beginning of the field name so that user code
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp60.C 
b/gcc/testsuite/g++.dg/cpp1z/decomp60.C
new file mode 100644
index ..b6117f3af583
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp60.C
@@ -0,0 +1,12 @@
+// PR c++/85889
+// { dg-do compile { target c++17 } }
+// { dg-options "" }
+
+struct X { int i, j; };
+void f() {
+  X x{};
+  auto [i, j] = x;
+  [&i]() { }; // { dg-warning "captured structured bindings" "" { target 
c++17_only } }
+  [i]() { }; // { dg-warning "captured structured bindings" "" { target 
c++17_only } }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp3.C 
b/gcc/testsuite/g++.dg/cpp2a/decomp3.C
index 5e77973d41f7..25ab83199757 100644
--- a/gcc/testsuite/g++.dg/cpp2a/decomp3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/decomp3.C
@@ -1,6 +1,6 @@
 // P1381R1
 // { dg-do compile { target c++11 } }
-// { dg-options "" }
+// { dg-options "-Wno-c++20-extensions" }
 
 struct Foo { int a : 1; int b; };


[gcc r15-329] c++: #pragma doesn't disable -Wunused-label [PR113582]

2024-05-08 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d9318caed3bbff8136d13e00dcfc020a59d10f78

commit r15-329-gd9318caed3bbff8136d13e00dcfc020a59d10f78
Author: Marek Polacek 
Date:   Wed Jan 24 18:06:48 2024 -0500

c++: #pragma doesn't disable -Wunused-label [PR113582]

The PR complains that

  void do_something(){
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-label"
start:;
#pragma GCC diagnostic pop
  } #1

doesn't work.  That's because we warn_for_unused_label only while we're
in finish_function, meaning we're at #1 where we're outside the #pragma
region.  We can use suppress_warning + warning_suppressed_p to fix this.

Note that I'm not using TREE_USED.  Propagating it in tsubst_stmt/LABEL_EXPR
from decl to label would mean that we don't warn in do_something2, but
I think we want the warning there: we're in a template and the goto is
a discarded statement.

PR c++/113582

gcc/c-family/ChangeLog:

* c-warn.cc (warn_for_unused_label): Don't warn if -Wunused-label 
has
been suppressed for the label.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_label_for_labeled_statement): 
suppress_warning
if it's not enabled at input_location.
* pt.cc (tsubst_stmt): Call copy_warning.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wunused-label-4.C: New test.

Diff:
---
 gcc/c-family/c-warn.cc  |  4 +++-
 gcc/cp/parser.cc|  6 +-
 gcc/cp/pt.cc|  9 +
 gcc/testsuite/g++.dg/warn/Wunused-label-4.C | 29 +
 4 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index bff87be05ae3..5b2d6805c790 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -2185,7 +2185,9 @@ warn_for_unused_label (tree label)
 {
   if (!TREE_USED (label))
 {
-  if (DECL_INITIAL (label))
+  if (warning_suppressed_p (label, OPT_Wunused_label))
+   /* Don't warn.  */;
+  else if (DECL_INITIAL (label))
warning (OPT_Wunused_label, "label %q+D defined but not used", label);
   else
warning (OPT_Wunused_label, "label %q+D declared but not defined", 
label);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index c4191200291d..7306ce9a8a8b 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -13108,7 +13108,11 @@ cp_parser_label_for_labeled_statement (cp_parser* 
parser, tree attributes)
   /* Anything else must be an ordinary label.  */
   label = finish_label_stmt (cp_parser_identifier (parser));
   if (label && TREE_CODE (label) == LABEL_DECL)
-   FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+   {
+ FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+ if (!warning_enabled_at (input_location, OPT_Wunused_label))
+   suppress_warning (label, OPT_Wunused_label);
+   }
   break;
 }
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1816bfd1f401..8787eabb9fdb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18837,11 +18837,12 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 case LABEL_EXPR:
   {
tree decl = LABEL_EXPR_LABEL (t);
-   tree label;
-
-   label = finish_label_stmt (DECL_NAME (decl));
+   tree label = finish_label_stmt (DECL_NAME (decl));
if (TREE_CODE (label) == LABEL_DECL)
- FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
+ {
+   FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
+   copy_warning (label, decl);
+ }
if (DECL_ATTRIBUTES (decl) != NULL_TREE)
  cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
   }
diff --git a/gcc/testsuite/g++.dg/warn/Wunused-label-4.C 
b/gcc/testsuite/g++.dg/warn/Wunused-label-4.C
new file mode 100644
index ..d194f043d215
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wunused-label-4.C
@@ -0,0 +1,29 @@
+// PR c++/113582
+// { dg-do compile { target c++17 } }
+// { dg-options "-Wunused-label" }
+
+template void
+do_something ()
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-label"
+start:
+  if constexpr(B)
+goto start;
+#pragma GCC diagnostic pop
+}
+
+template void
+do_something2 ()
+{
+start: // { dg-warning "defined but not used" }
+  if constexpr(B)
+goto start;
+}
+
+void
+g ()
+{
+  do_something<0>();
+  do_something2<0>();
+}


[gcc r15-301] c++: DECL_DECOMPOSITION_P cleanup

2024-05-07 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:7887d808876c00e682e11c19caae1a0dbc9fa3a8

commit r15-301-g7887d808876c00e682e11c19caae1a0dbc9fa3a8
Author: Marek Polacek 
Date:   Fri Mar 1 13:36:51 2024 -0500

c++: DECL_DECOMPOSITION_P cleanup

DECL_DECOMPOSITION_P already checks VAR_P but we repeat the check
in a lot of places.

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): Don't check VAR_P before
DECL_DECOMPOSITION_P.
* init.cc (build_aggr_init): Likewise.
* parser.cc (cp_parser_range_for): Likewise.
(do_range_for_auto_deduction): Likewise.
(cp_convert_range_for): Likewise.
(cp_convert_omp_range_for): Likewise.
(cp_finish_omp_range_for): Likewise.
* pt.cc (extract_locals_r): Likewise.
(tsubst_omp_for_iterator): Likewise.
(tsubst_decomp_names): Likewise.
(tsubst_stmt): Likewise.
* typeck.cc (maybe_warn_about_returning_address_of_local): Likewise.

Diff:
---
 gcc/cp/decl.cc   |  3 +--
 gcc/cp/init.cc   |  2 +-
 gcc/cp/parser.cc | 11 ---
 gcc/cp/pt.cc | 11 +++
 gcc/cp/typeck.cc |  3 +--
 5 files changed, 10 insertions(+), 20 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b112b70659f8..e02562466a74 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1938,8 +1938,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
  inform (olddecl_loc, "previous declaration %q#D", olddecl);
  return error_mark_node;
}
-  else if ((VAR_P (olddecl) && DECL_DECOMPOSITION_P (olddecl))
-  || (VAR_P (newdecl) && DECL_DECOMPOSITION_P (newdecl)))
+  else if (DECL_DECOMPOSITION_P (olddecl) || DECL_DECOMPOSITION_P 
(newdecl))
/* A structured binding must be unique in its declarative region.  */;
   else if (DECL_IMPLICIT_TYPEDEF_P (olddecl)
   || DECL_IMPLICIT_TYPEDEF_P (newdecl))
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index a93ce00800c4..c1b5b7425c9b 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -2008,7 +2008,7 @@ build_aggr_init (tree exp, tree init, int flags, 
tsubst_flags_t complain)
   tree itype = init ? TREE_TYPE (init) : NULL_TREE;
   int from_array = 0;
 
-  if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
+  if (DECL_DECOMPOSITION_P (exp))
{
  from_array = 1;
  init = mark_rvalue_use (init);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 66ce161252c7..775067ed4bc5 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -14122,7 +14122,6 @@ cp_parser_range_for (cp_parser *parser, tree scope, 
tree init, tree range_decl,
  /* For decomposition declaration get all of the corresponding
 declarations out of the way.  */
  if (TREE_CODE (v) == ARRAY_REF
- && VAR_P (TREE_OPERAND (v, 0))
  && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
{
  tree d = range_decl;
@@ -14243,7 +14242,7 @@ do_range_for_auto_deduction (tree decl, tree 
range_expr, cp_decomp *decomp)
iter_decl, auto_node,
tf_warning_or_error,
adc_variable_type);
- if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+ if (DECL_DECOMPOSITION_P (decl))
cp_finish_decomp (decl, decomp);
}
 }
@@ -14442,7 +14441,7 @@ cp_convert_range_for (tree statement, tree range_decl, 
tree range_expr,
   cp_finish_decl (range_decl, deref_begin,
  /*is_constant_init*/false, NULL_TREE,
  LOOKUP_ONLYCONVERTING, decomp);
-  if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl))
+  if (DECL_DECOMPOSITION_P (range_decl))
 cp_finish_decomp (range_decl, decomp);
 
   warn_for_range_copy (range_decl, deref_begin);
@@ -0,7 +44439,6 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
{
  tree v = DECL_VALUE_EXPR (decl);
  if (TREE_CODE (v) == ARRAY_REF
- && VAR_P (TREE_OPERAND (v, 0))
  && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
{
  d = TREE_OPERAND (v, 0);
@@ -44545,7 +44543,6 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
 {
   tree v = DECL_VALUE_EXPR (orig_decl);
   if (TREE_CODE (v) == ARRAY_REF
- && VAR_P (TREE_OPERAND (v, 0))
  && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
{
  tree d = orig_decl;
@@ -44623,7 +44620,7 @@ cp_finish_omp_range_for (tree orig, tree begin)
   tree decl = TREE_VEC_ELT (TREE_CHAIN (orig), 2);
   cp_decomp decomp_d, *decomp = NULL;
 
-  if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+  if (DECL_DECOMPOSITION_P (decl))
 {
   decomp = &decomp_d;
   decomp_d.decl = TREE_VEC_ELT (TREE_CHAIN (orig), 3);
@@ -44649,7 +44646,7 @@ cp_finish_omp_range_for (

[gcc r14-10075] testsuite: prune -freport-bug output

2024-04-22 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:0db19228a9feba5a8f4e13b21f25f3aa8a6c5e85

commit r14-10075-g0db19228a9feba5a8f4e13b21f25f3aa8a6c5e85
Author: Marek Polacek 
Date:   Fri Apr 19 13:51:41 2024 -0400

testsuite: prune -freport-bug output

When the compiler defaults to -freport-bug, a few dg-ice tests fail
with:

Excess errors:
Preprocessed source stored into /tmp/cc6hldZ0.out file, please attach this 
to your bugreport.

We could add -fno-report-bug to those tests.  But it seems to me that a
better fix would be to prune the "Preprocessed source stored..." message
in prune_gcc_output.

gcc/testsuite/ChangeLog:

* lib/prune.exp (prune_gcc_output): Also prune -freport-bug output.

Reviewed-by: Jakub Jelinek 

Diff:
---
 gcc/testsuite/lib/prune.exp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index f3d3c99fbcb..d00d37f015f 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -51,6 +51,7 @@ proc prune_gcc_output { text } {
 regsub -all "(^|\n)\[^\n\]*: re(compiling|linking)\[^\n\]*" $text "" text
 regsub -all "(^|\n)Please submit.*instructions\[^\n\]*" $text "" text
 regsub -all "(^|\n)\[0-9\]\[0-9\]* errors\." $text "" text
+regsub -all "(^|\n)Preprocessed.*bugreport\[^\n\]*" $text "" text
 
 # Diagnostic inclusion stack
 regsub -all "(^|\n)(In file)?\[ \]+included from \[^\n\]*" $text "" text


[gcc r14-9950] c++: ICE with temporary of class type in array DMI [PR109966]

2024-04-12 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:6039925631780741ba77666ef2ef743aa2a925a8

commit r14-9950-g6039925631780741ba77666ef2ef743aa2a925a8
Author: Marek Polacek 
Date:   Mon Mar 11 17:45:55 2024 -0400

c++: ICE with temporary of class type in array DMI [PR109966]

This ICE started with the fairly complicated r13-765.  We crash in
gimplify_var_or_parm_decl because a stray VAR_DECL leaked there.
The problem is ultimately that potential_prvalue_result_of wasn't
correctly handling arrays and replace_placeholders_for_class_temp_r
replaced a PLACEHOLDER_EXPR in a TARGET_EXPR which is used in the
context of copy elision.  If I have

  M m[2] = { M{""}, M{""} };

then we don't invoke the M(const M&) copy-ctor.

One part of the fix is to use TARGET_EXPR_ELIDING_P rather than
potential_prvalue_result_of.  That unfortunately doesn't handle the
case like

  struct N { N(M); };
  N arr[2] = { M{""}, M{""} };

because TARGET_EXPRs that initialize a function argument are not
marked TARGET_EXPR_ELIDING_P even though gimplify_arg drops such
TARGET_EXPRs on the floor.  We can use a pset to avoid replacing
placeholders in them.

I made an attempt to use set_target_expr_eliding in
convert_for_arg_passing but that regressed constexpr-diag1.C, and does
not seem like a prudent change in stage 4 anyway.

PR c++/109966

gcc/cp/ChangeLog:

* typeck2.cc (potential_prvalue_result_of): Remove.
(replace_placeholders_for_class_temp_r): Check 
TARGET_EXPR_ELIDING_P.
Use a pset.  Don't replace_placeholders in TARGET_EXPRs that 
initialize
a function argument.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/nsdmi-aggr20.C: New test.
* g++.dg/cpp1y/nsdmi-aggr21.C: New test.

Diff:
---
 gcc/cp/typeck2.cc | 55 +---
 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr20.C | 17 +
 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr21.C | 59 +++
 3 files changed, 92 insertions(+), 39 deletions(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 31198b2f9f5..2985bfdf9ec 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1399,41 +1399,6 @@ digest_init_flags (tree type, tree init, int flags, 
tsubst_flags_t complain)
   return digest_init_r (type, init, 0, flags, complain);
 }
 
-/* Return true if SUBOB initializes the same object as FULL_EXPR.
-   For instance:
-
- A a = A{};  // initializer
- A a = (A{});// initializer
- A a = (1, A{}); // initializer
- A a = true ? A{} : A{};  // initializer
- auto x = A{}.x; // temporary materialization
- auto x = foo(A{});  // temporary materialization
-
-   FULL_EXPR is the whole expression, SUBOB is its TARGET_EXPR subobject.  */
-
-static bool
-potential_prvalue_result_of (tree subob, tree full_expr)
-{
-  if (subob == full_expr)
-return true;
-  else if (TREE_CODE (full_expr) == TARGET_EXPR)
-{
-  tree init = TARGET_EXPR_INITIAL (full_expr);
-  if (TREE_CODE (init) == COND_EXPR)
-   return (potential_prvalue_result_of (subob, TREE_OPERAND (init, 1))
-   || potential_prvalue_result_of (subob, TREE_OPERAND (init, 2)));
-  else if (TREE_CODE (init) == COMPOUND_EXPR)
-   return potential_prvalue_result_of (subob, TREE_OPERAND (init, 1));
-  /* ??? I don't know if this can be hit.  */
-  else if (TREE_CODE (init) == PAREN_EXPR)
-   {
- gcc_checking_assert (false);
- return potential_prvalue_result_of (subob, TREE_OPERAND (init, 0));
-   }
-}
-  return false;
-}
-
 /* Callback to replace PLACEHOLDER_EXPRs in a TARGET_EXPR (which isn't used
in the context of guaranteed copy elision).  */
 
@@ -1441,11 +1406,13 @@ static tree
 replace_placeholders_for_class_temp_r (tree *tp, int *, void *data)
 {
   tree t = *tp;
-  tree full_expr = *static_cast(data);
+  auto pset = static_cast *>(data);
 
   /* We're looking for a TARGET_EXPR nested in the whole expression.  */
   if (TREE_CODE (t) == TARGET_EXPR
-  && !potential_prvalue_result_of (t, full_expr))
+  /* That serves as temporary materialization, not an initializer.  */
+  && !TARGET_EXPR_ELIDING_P (t)
+  && !pset->add (t))
 {
   tree init = TARGET_EXPR_INITIAL (t);
   while (TREE_CODE (init) == COMPOUND_EXPR)
@@ -1460,6 +1427,16 @@ replace_placeholders_for_class_temp_r (tree *tp, int *, 
void *data)
  gcc_checking_assert (!find_placeholders (init));
}
 }
+  /* TARGET_EXPRs initializing function arguments are not marked as eliding,
+ even though gimplify_arg drops them on the floor.  Don't go replacing
+ placeholders in them.  */
+  else if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
+for (int i = 0; i < call_expr_nargs (t); ++i)
+  {
+   tree arg =

[gcc r14-9903] target: missing -Whardened with -fcf-protection=none [PR114606]

2024-04-10 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:b8b148bc22673689fda19711b428b544462be2e4

commit r14-9903-gb8b148bc22673689fda19711b428b544462be2e4
Author: Marek Polacek 
Date:   Fri Apr 5 12:37:19 2024 -0400

target: missing -Whardened with -fcf-protection=none [PR114606]

-Whardened warns when -fhardened couldn't enable a hardening option
because that option was disabled on the command line, e.g.:

$ ./cc1plus -quiet g.C -fhardened -O2 -fstack-protector
cc1plus: warning: '-fstack-protector-strong' is not enabled by '-fhardened' 
because it was specified on the command line [-Whardened]

but it doesn't work as expected with -fcf-protection=none:

$ ./cc1plus -quiet g.C -fhardened -O2 -fcf-protection=none

because we're checking == CF_NONE which doesn't distinguish between nothing
and -fcf-protection=none.  I should have used opts_set, like below.

PR target/114606

gcc/ChangeLog:

* config/i386/i386-options.cc (ix86_option_override_internal): Use
opts_set rather than checking == CF_NONE.

gcc/testsuite/ChangeLog:

* gcc.target/i386/fhardened-1.c: New test.
* gcc.target/i386/fhardened-2.c: New test.

Reviewed-by: Jakub Jelinek 

Diff:
---
 gcc/config/i386/i386-options.cc | 2 +-
 gcc/testsuite/gcc.target/i386/fhardened-1.c | 8 
 gcc/testsuite/gcc.target/i386/fhardened-2.c | 8 
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index 7896d576977..68a2e1c6910 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3242,7 +3242,7 @@ ix86_option_override_internal (bool main_args_p,
  on the command line.  */
   if (opts->x_flag_hardened && cf_okay_p)
 {
-  if (opts->x_flag_cf_protection == CF_NONE)
+  if (!opts_set->x_flag_cf_protection)
opts->x_flag_cf_protection = CF_FULL;
   else if (opts->x_flag_cf_protection != CF_FULL)
warning_at (UNKNOWN_LOCATION, OPT_Whardened,
diff --git a/gcc/testsuite/gcc.target/i386/fhardened-1.c 
b/gcc/testsuite/gcc.target/i386/fhardened-1.c
new file mode 100644
index 000..55d1718ff55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/fhardened-1.c
@@ -0,0 +1,8 @@
+/* PR target/114606 */
+/* { dg-options "-fhardened -O2 -fcf-protection=none" } */
+
+#ifdef __CET__
+# error "-fcf-protection enabled when it should not be"
+#endif
+
+/* { dg-warning ".-fcf-protection=full. is not enabled by .-fhardened. because 
it was specified" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/i386/fhardened-2.c 
b/gcc/testsuite/gcc.target/i386/fhardened-2.c
new file mode 100644
index 000..9b8c1381c19
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/fhardened-2.c
@@ -0,0 +1,8 @@
+/* PR target/114606 */
+/* { dg-options "-fhardened -O2" } */
+
+#if __CET__ != 3
+# error "-fcf-protection not enabled"
+#endif
+
+/* { dg-bogus ".-fcf-protection=full. is not enabled by .-fhardened. because 
it was specified" "" { target *-*-* } 0 } */


[gcc r14-9815] c++: add fixed test [PR91079]

2024-04-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:2b2d3a135a43cbafadd8957e0b2543f38c390437

commit r14-9815-g2b2d3a135a43cbafadd8957e0b2543f38c390437
Author: Marek Polacek 
Date:   Fri Apr 5 13:40:33 2024 -0400

c++: add fixed test [PR91079]

Fixed by r12-2975.

PR c++/91079
DR 1881

gcc/testsuite/ChangeLog:

* g++.dg/ext/is_std_layout5.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/ext/is_std_layout5.C | 13 +
 1 file changed, 13 insertions(+)

diff --git a/gcc/testsuite/g++.dg/ext/is_std_layout5.C 
b/gcc/testsuite/g++.dg/ext/is_std_layout5.C
new file mode 100644
index 000..875f3c0948d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_std_layout5.C
@@ -0,0 +1,13 @@
+// PR c++/91079
+// DR 1881 - Standard-layout classes and unnamed bit-fields
+// { dg-do compile { target c++11 } }
+
+struct A { int a : 4; };
+struct B : A { int b : 3; };
+static_assert(__is_standard_layout(A), "");
+static_assert(!__is_standard_layout(B), "");
+
+struct C { int : 0; };
+struct D : C { int : 0; };
+static_assert(__is_standard_layout(C), "");
+static_assert(!__is_standard_layout(D), "");


[gcc r14-9810] c-family: remove dead #undef

2024-04-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:e4d074321bcafa6504ee6b77754b4450a4622f9d

commit r14-9810-ge4d074321bcafa6504ee6b77754b4450a4622f9d
Author: Marek Polacek 
Date:   Thu Apr 4 19:28:00 2024 -0400

c-family: remove dead #undef

The #undef was added in r0-90320-g100d537d7a7b5c but it never did
anything.

gcc/c-family/ChangeLog:

* c-warn.cc (warn_about_parentheses): Remove an #undef.

Diff:
---
 gcc/c-family/c-warn.cc | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 8168696fa45..bff87be05ae 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -2176,7 +2176,6 @@ warn_about_parentheses (location_t loc, enum tree_code 
code,
}
   return;
 }
-#undef NOT_A_BOOLEAN_EXPR_P
 }
 
 /* If LABEL (a LABEL_DECL) has not been used, issue a warning.  */


[gcc r14-9809] c++: constexpr error with fn redecl in local scope [PR111132]

2024-04-05 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:8c9063825ce726fcbbc067d8a6d062cc2d4acf5e

commit r14-9809-g8c9063825ce726fcbbc067d8a6d062cc2d4acf5e
Author: Marek Polacek 
Date:   Tue Apr 2 12:59:38 2024 -0400

c++: constexpr error with fn redecl in local scope [PR32]

We evaluate constexpr functions on the original, pre-genericization bodies.
That means that the function body we're evaluating will not have gone
through cp_genericize_r's "Map block scope extern declarations to visible
declarations with the same name and type in outer scopes if any".  Here:

  constexpr bool bar() { return true; } // #1
  constexpr bool foo() {
constexpr bool bar(void); // #2
return bar();
  }

it means that we:
1) register_constexpr_fundef (#1)
2) cp_genericize (#1)
   nothing interesting happens
3) register_constexpr_fundef (foo)
   does copy_fn, so we have two copies of the BIND_EXPR
4) cp_genericize (foo)
   this remaps #2 to #1, but only on one copy of the BIND_EXPR
5) retrieve_constexpr_fundef (foo)
   we find it, no problem
6) retrieve_constexpr_fundef (#2)
   and here #2 isn't found in constexpr_fundef_table, because
   we're working on the BIND_EXPR copy where #2 wasn't mapped to #1
   so we fail.  We've only registered #1.

It should work to use DECL_LOCAL_DECL_ALIAS (which used to be
extern_decl_map).  We evaluate constexpr functions on pre-cp_fold
bodies to avoid diagnostic problems, but the remapping I'm proposing
should not interfere with diagnostics.

This is not a problem for a global scope redeclaration; there we go
through duplicate_decls which keeps the DECL_UID:
  DECL_UID (olddecl) = olddecl_uid;
and DECL_UID is what constexpr_fundef_hasher::hash uses.

PR c++/32

gcc/cp/ChangeLog:

* constexpr.cc (get_function_named_in_call): Use
cp_get_fndecl_from_callee.
* cvt.cc (cp_get_fndecl_from_callee): If there's a
DECL_LOCAL_DECL_ALIAS, use it.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/constexpr.cc   | 10 --
 gcc/cp/cvt.cc | 18 --
 gcc/testsuite/g++.dg/cpp0x/constexpr-redeclaration3.C | 13 +
 gcc/testsuite/g++.dg/cpp0x/constexpr-redeclaration4.C | 14 ++
 4 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fa346fe01c9..410ccdf597f 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -702,16 +702,14 @@ build_constexpr_constructor_member_initializers (tree 
type, tree body)
 
 /* We have an expression tree T that represents a call, either CALL_EXPR
or AGGR_INIT_EXPR.  If the call is lexically to a named function,
-   retrun the _DECL for that function.  */
+   return the _DECL for that function.  */
 
 static tree
 get_function_named_in_call (tree t)
 {
-  tree fun = cp_get_callee (t);
-  if (fun && TREE_CODE (fun) == ADDR_EXPR
-  && TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL)
-fun = TREE_OPERAND (fun, 0);
-  return fun;
+  tree callee = cp_get_callee (t);
+  tree fun = cp_get_fndecl_from_callee (callee, /*fold*/false);
+  return fun ? fun : callee;
 }
 
 /* Subroutine of check_constexpr_fundef.  BODY is the body of a function
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index cbed847b343..db086c017e8 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1001,8 +1001,22 @@ cp_get_fndecl_from_callee (tree fn, bool fold /* = true 
*/)
 {
   if (fn == NULL_TREE)
 return fn;
+
+  /* We evaluate constexpr functions on the original, pre-genericization
+ bodies.  So block-scope extern declarations have not been mapped to
+ declarations in outer scopes.  Use the namespace-scope declaration,
+ if any, so that retrieve_constexpr_fundef can find it (PR32).  */
+  auto fn_or_local_alias = [] (tree f)
+{
+  if (DECL_LOCAL_DECL_P (f))
+   if (tree alias = DECL_LOCAL_DECL_ALIAS (f))
+ if (alias != error_mark_node)
+   return alias;
+  return f;
+};
+
   if (TREE_CODE (fn) == FUNCTION_DECL)
-return fn;
+return fn_or_local_alias (fn);
   tree type = TREE_TYPE (fn);
   if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
 return NULL_TREE;
@@ -1013,7 +1027,7 @@ cp_get_fndecl_from_callee (tree fn, bool fold /* = true 
*/)
   || TREE_CODE (fn) == FDESC_EXPR)
 fn = TREE_OPERAND (fn, 0);
   if (TREE_CODE (fn) == FUNCTION_DECL)
-return fn;
+return fn_or_local_alias (fn);
   return NULL_TREE;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-redeclaration3.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-redeclaration3.C
new file mode 100644
index 000..2b41b456fc3
--- /dev/null
+++ b/gcc/testsuite/g

[gcc r14-9759] c++: make __is_array return false for T[0] [PR114479]

2024-04-02 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:2f2924078ce51c2a0da3ad8f958f2d1de533969a

commit r14-9759-g2f2924078ce51c2a0da3ad8f958f2d1de533969a
Author: Marek Polacek 
Date:   Mon Apr 1 12:55:46 2024 -0400

c++: make __is_array return false for T[0] [PR114479]

When we switched to using the __is_array built-in trait to implement
std::is_array in r14-6623-g7fd9c349e45534, we started saying that
T[0] is an array.  There are various opinions as to whether that is
the best answer, but it seems prudent to keep the GCC 13 result.

PR c++/114479

gcc/cp/ChangeLog:

* semantics.cc (trait_expr_value) : Return false
for zero-sized arrays.

gcc/testsuite/ChangeLog:

* g++.dg/ext/is_array.C: Extend.

Diff:
---
 gcc/cp/semantics.cc |  8 +++-
 gcc/testsuite/g++.dg/ext/is_array.C | 12 
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9838331d2a9..0015ff4fb62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12439,7 +12439,13 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
   return CP_AGGREGATE_TYPE_P (type1);
 
 case CPTK_IS_ARRAY:
-  return type_code1 == ARRAY_TYPE;
+  return (type_code1 == ARRAY_TYPE
+ /* We don't want to report T[0] as being an array type.
+This is for compatibility with an implementation of
+std::is_array by template argument deduction, because
+compute_array_index_type_loc rejects a zero-size array
+in SFINAE context.  */
+ && !(TYPE_SIZE (type1) && integer_zerop (TYPE_SIZE (type1;
 
 case CPTK_IS_ASSIGNABLE:
   return is_xible (MODIFY_EXPR, type1, type2);
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C 
b/gcc/testsuite/g++.dg/ext/is_array.C
index f1a6e08b87a..84993266629 100644
--- a/gcc/testsuite/g++.dg/ext/is_array.C
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-options "" }
 
 #define SA(X) static_assert((X),#X)
 
@@ -10,18 +11,29 @@
 
 class ClassType { };
 
+constexpr int sz0 = 0;
+constexpr int sz2 = 2;
+
 SA_TEST_CATEGORY(__is_array, int[2], true);
 SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[0], false);
 SA_TEST_CATEGORY(__is_array, int[2][3], true);
 SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, int[0][3], false);
+SA_TEST_CATEGORY(__is_array, int[3][0], false);
 SA_TEST_CATEGORY(__is_array, float*[2], true);
 SA_TEST_CATEGORY(__is_array, float*[], true);
 SA_TEST_CATEGORY(__is_array, float*[2][3], true);
 SA_TEST_CATEGORY(__is_array, float*[][3], true);
 SA_TEST_CATEGORY(__is_array, ClassType[2], true);
 SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[0], false);
 SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
 SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[0][3], false);
+SA_TEST_CATEGORY(__is_array, ClassType[2][0], false);
+SA_TEST_CATEGORY(__is_array, int[sz2], true);
+SA_TEST_CATEGORY(__is_array, int[sz0], false);
 
 // Sanity check.
 SA_TEST_CATEGORY(__is_array, ClassType, false);


[gcc r13-8560] c++: ICE with scoped enum in switch condition [PR103825]

2024-04-02 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:22510e4a68aa9ca850db34ae62c21c58442d8ab3

commit r13-8560-g22510e4a68aa9ca850db34ae62c21c58442d8ab3
Author: Marek Polacek 
Date:   Fri Mar 29 16:59:37 2024 -0400

c++: ICE with scoped enum in switch condition [PR103825]

Here we ICE when gimplifying

  enum class Type { Pawn };
  struct Piece {
Type type : 4;
  };
  void foo() {
switch (Piece().type)
  case Type::Pawn:;
  }

because we ended up with TYPE_PRECISION (cond) < TYPE_PRECISION (case).
That's because the case expr type here is the unlowered type Type,
whereas the conditional's type is the lowered .  This
is not supposed to happen: see the comment in pop_switch around the
is_bitfield_expr_with_lowered_type check.

But here we did not revert to the lowered SWITCH_STMT_TYPE, because
the conditional contains a TARGET_EXPR, which has side-effects, which
means that finish_switch_cond -> maybe_cleanup_point_expr wraps it
in a CLEANUP_POINT_EXPR.  And is_bitfield_expr_with_lowered_type does
not see through those.

PR c++/103825

gcc/cp/ChangeLog:

* typeck.cc (is_bitfield_expr_with_lowered_type): Handle
CLEANUP_POINT_EXPR.

gcc/testsuite/ChangeLog:

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

(cherry picked from commit daa2e7c7ffe49b788357f7f2c9ef1c9b125c1f8c)

Diff:
---
 gcc/cp/typeck.cc|  1 +
 gcc/testsuite/g++.dg/cpp0x/enum44.C | 30 ++
 2 files changed, 31 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 56bb21ab251..81bc9edd955 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -2400,6 +2400,7 @@ is_bitfield_expr_with_lowered_type (const_tree exp)
 case NEGATE_EXPR:
 case NON_LVALUE_EXPR:
 case BIT_NOT_EXPR:
+case CLEANUP_POINT_EXPR:
   return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
 
 case COMPONENT_REF:
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum44.C 
b/gcc/testsuite/g++.dg/cpp0x/enum44.C
new file mode 100644
index 000..92408c92217
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum44.C
@@ -0,0 +1,30 @@
+// PR c++/103825
+// { dg-do compile { target c++11 } }
+
+enum class Type { Pawn };
+struct Piece {
+  Type type : 4;
+};
+
+void
+foo ()
+{
+  switch (Piece().type)
+case Type::Pawn:;
+
+  auto x = Piece().type;
+  switch (x)
+case Type::Pawn:;
+}
+
+enum class En {A};
+struct St {En field :1;};
+
+void
+bar ()
+{
+  volatile St s = {En::A};
+  switch(s.field) {
+case En::A : break;
+  }
+}


[gcc r14-9758] c++: ICE with scoped enum in switch condition [PR103825]

2024-04-02 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:daa2e7c7ffe49b788357f7f2c9ef1c9b125c1f8c

commit r14-9758-gdaa2e7c7ffe49b788357f7f2c9ef1c9b125c1f8c
Author: Marek Polacek 
Date:   Fri Mar 29 16:59:37 2024 -0400

c++: ICE with scoped enum in switch condition [PR103825]

Here we ICE when gimplifying

  enum class Type { Pawn };
  struct Piece {
Type type : 4;
  };
  void foo() {
switch (Piece().type)
  case Type::Pawn:;
  }

because we ended up with TYPE_PRECISION (cond) < TYPE_PRECISION (case).
That's because the case expr type here is the unlowered type Type,
whereas the conditional's type is the lowered .  This
is not supposed to happen: see the comment in pop_switch around the
is_bitfield_expr_with_lowered_type check.

But here we did not revert to the lowered SWITCH_STMT_TYPE, because
the conditional contains a TARGET_EXPR, which has side-effects, which
means that finish_switch_cond -> maybe_cleanup_point_expr wraps it
in a CLEANUP_POINT_EXPR.  And is_bitfield_expr_with_lowered_type does
not see through those.

PR c++/103825

gcc/cp/ChangeLog:

* typeck.cc (is_bitfield_expr_with_lowered_type): Handle
CLEANUP_POINT_EXPR.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/typeck.cc|  1 +
 gcc/testsuite/g++.dg/cpp0x/enum44.C | 30 ++
 2 files changed, 31 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 88ed38e4f30..e5a52dc2b39 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -2400,6 +2400,7 @@ is_bitfield_expr_with_lowered_type (const_tree exp)
 case NEGATE_EXPR:
 case NON_LVALUE_EXPR:
 case BIT_NOT_EXPR:
+case CLEANUP_POINT_EXPR:
   return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
 
 case COMPONENT_REF:
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum44.C 
b/gcc/testsuite/g++.dg/cpp0x/enum44.C
new file mode 100644
index 000..92408c92217
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum44.C
@@ -0,0 +1,30 @@
+// PR c++/103825
+// { dg-do compile { target c++11 } }
+
+enum class Type { Pawn };
+struct Piece {
+  Type type : 4;
+};
+
+void
+foo ()
+{
+  switch (Piece().type)
+case Type::Pawn:;
+
+  auto x = Piece().type;
+  switch (x)
+case Type::Pawn:;
+}
+
+enum class En {A};
+struct St {En field :1;};
+
+void
+bar ()
+{
+  volatile St s = {En::A};
+  switch(s.field) {
+case En::A : break;
+  }
+}


[gcc r14-9674] c++: add fixed test [PR100557]

2024-03-26 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:c0e199e4dbe652cd16d7248f0bfe166540f5d95b

commit r14-9674-gc0e199e4dbe652cd16d7248f0bfe166540f5d95b
Author: Marek Polacek 
Date:   Tue Mar 26 10:39:48 2024 -0400

c++: add fixed test [PR100557]

We used to hit the "Error reporting routines re-entered." ICE here but
it was fixed by Patrick's r14-3809.

PR c++/100557

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/testsuite/g++.dg/cpp2a/concepts-pr100557.C | 21 +
 1 file changed, 21 insertions(+)

diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr100557.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr100557.C
new file mode 100644
index 000..8dcd0eaca51
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr100557.C
@@ -0,0 +1,21 @@
+// PR c++/100557
+// { dg-do compile { target c++20 } }
+
+template  _Tp declval();
+
+struct print_tag_;
+
+bool tag_invoke(print_tag_, auto);
+bool tag_invoke(print_tag_, auto obj) requires requires { *obj; };
+
+template 
+auto try_tag_invoke() noexcept(tag_invoke(declval, declval()...)) 
// { dg-error "no matching function for call" }
+-> decltype(tag_invoke(CPO(), declval()...));
+
+struct print_tag_ {
+  void operator()(auto... args) noexcept(noexcept( try_tag_invoke()));
+} print;
+
+void foo() {
+  print(0);
+}


[gcc r14-9659] c++: ICE with noexcept and local specialization, again [PR114349]

2024-03-25 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:8651991fe2ea90a7276e91673b15b5c3865f14d7

commit r14-9659-g8651991fe2ea90a7276e91673b15b5c3865f14d7
Author: Marek Polacek 
Date:   Fri Mar 15 09:23:28 2024 -0400

c++: ICE with noexcept and local specialization, again [PR114349]

Patrick noticed that my r14-9339-gdc6c3bfb59baab patch is wrong;
we're dealing with a noexcept-spec there, not a noexcept-expr, so
setting cp_noexcept_operand et al is incorrect.  Back to the drawing
board then.

To fix noexcept84.C, we should probably avoid doing push_to_top_level
in certain cases.  maybe_push_to_top_level didn't work here as-is, so
I changed it to not push to top level if decl_function_context is
non-null, when we are not dealing with a lambda.

This also fixes c++/114349, introduced by r14-9339.

PR c++/114349

gcc/cp/ChangeLog:

* name-lookup.cc (maybe_push_to_top_level): For a non-lambda,
don't push to top level if decl_function_context is non-null.
* pt.cc (maybe_instantiate_noexcept): Use maybe_push_to_top_level.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept85.C: New test.
* g++.dg/cpp0x/noexcept86.C: New test.

Diff:
---
 gcc/cp/name-lookup.cc   | 11 +++
 gcc/cp/pt.cc| 11 ++-
 gcc/testsuite/g++.dg/cpp0x/noexcept85.C | 33 +
 gcc/testsuite/g++.dg/cpp0x/noexcept86.C | 25 +
 4 files changed, 67 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index dce4caf8981..7af7f00e34c 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -8664,10 +8664,13 @@ maybe_push_to_top_level (tree d)
 {
   /* Push if D isn't function-local, or is a lambda function, for which name
  resolution is already done.  */
-  bool push_to_top
-= !(current_function_decl
-   && !LAMBDA_FUNCTION_P (d)
-   && decl_function_context (d) == current_function_decl);
+  const bool push_to_top
+= (LAMBDA_FUNCTION_P (d)
+   || (TREE_CODE (d) == TYPE_DECL
+  && TREE_TYPE (d)
+  && LAMBDA_TYPE_P (TREE_TYPE (d)))
+   || !current_function_decl
+   || !decl_function_context (d));
 
   if (push_to_top)
 push_to_top_level ();
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8cf0d5b7a8d..7b00a8615d2 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -26855,7 +26855,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
}
   else if (push_tinst_level (fn))
{
- push_to_top_level ();
+ const bool push_to_top = maybe_push_to_top_level (fn);
  push_access_scope (fn);
  push_deferring_access_checks (dk_no_deferred);
  input_location = DECL_SOURCE_LOCATION (fn);
@@ -26878,17 +26878,10 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
  if (orig_fn)
++processing_template_decl;
 
- ++cp_unevaluated_operand;
- ++c_inhibit_evaluation_warnings;
- ++cp_noexcept_operand;
  /* Do deferred instantiation of the noexcept-specifier.  */
  noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex),
  DEFERRED_NOEXCEPT_ARGS (noex),
  tf_warning_or_error, fn);
- --cp_unevaluated_operand;
- --c_inhibit_evaluation_warnings;
- --cp_noexcept_operand;
-
  /* Build up the noexcept-specification.  */
  spec = build_noexcept_spec (noex, tf_warning_or_error);
 
@@ -26898,7 +26891,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
  pop_deferring_access_checks ();
  pop_access_scope (fn);
  pop_tinst_level ();
- pop_from_top_level ();
+ maybe_pop_from_top_level (push_to_top);
}
   else
spec = noexcept_false_spec;
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept85.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept85.C
new file mode 100644
index 000..b415bb46bc9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept85.C
@@ -0,0 +1,33 @@
+// PR c++/114349
+// { dg-do compile { target c++11 } }
+
+using A = struct {};
+template  class, typename, typename>
+using B = A;
+template 
+using C = typename T::D;
+struct E {
+  using D = B;
+};
+template  constexpr bool foo (A) { return false; }
+template  struct F {
+  using G = T;
+  using H = E;
+  F(const F &);
+  void operator=(F) noexcept(foo  (H::D{}));
+};
+template 
+using I = F;
+template 
+using J = I;
+struct K {
+  typedef J L;
+  L k;
+  K();
+};
+struct M {
+  bool bar () const;
+  K::L m;
+};
+K n;
+bool M::bar () const { n.k = m; return true; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept86.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept86.C
new file mode 100644
index 000..2d040c090f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept86.C
@@ -0,0 +1,25 @@
+// PR c++/114349
+// { d

[gcc r14-9658] c++: broken direct-init with trailing array member [PR114439]

2024-03-25 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:de0886d48032332d10e4acb5d15c8789b281b6fe

commit r14-9658-gde0886d48032332d10e4acb5d15c8789b281b6fe
Author: Marek Polacek 
Date:   Mon Mar 25 15:32:20 2024 -0400

c++: broken direct-init with trailing array member [PR114439]

can_init_array_with_p is wrongly saying that the init for 's' here:

  struct S {
int *list = arr;
int arr[];
  };

  struct A {
A() {}
S s[2]{};
  };

is invalid.  But as process_init_constructor_array says, for "non-constant
initialization of trailing elements with no explicit initializers" we use
a VEC_INIT_EXPR wrapped in a TARGET_EXPR, built in process_init_constructor.

Unfortunately we didn't have a test for this scenario so I didn't
realize can_init_array_with_p must handle it.

PR c++/114439

gcc/cp/ChangeLog:

* init.cc (can_init_array_with_p): Return true for a VEC_INIT_EXPR
wrapped in a TARGET_EXPR.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/init.cc  |  6 +-
 gcc/testsuite/g++.dg/init/array65.C | 38 +
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index dbd37d47cbf..a93ce00800c 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -950,12 +950,16 @@ can_init_array_with_p (tree type, tree init)
  mem-initializers of a constructor.  */
   if (DECL_DEFAULTED_FN (current_function_decl))
 return true;
-  /* As an extension, we allow copying from a compound literal.  */
   if (TREE_CODE (init) == TARGET_EXPR)
 {
   init = TARGET_EXPR_INITIAL (init);
+  /* As an extension, we allow copying from a compound literal.  */
   if (TREE_CODE (init) == CONSTRUCTOR)
return CONSTRUCTOR_C99_COMPOUND_LITERAL (init);
+  /* VEC_INIT_EXPR is used for non-constant initialization of trailing
+elements with no explicit initializers.  */
+  else if (TREE_CODE (init) == VEC_INIT_EXPR)
+   return true;
 }
 
   return false;
diff --git a/gcc/testsuite/g++.dg/init/array65.C 
b/gcc/testsuite/g++.dg/init/array65.C
new file mode 100644
index 000..0b144f45a9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array65.C
@@ -0,0 +1,38 @@
+// PR c++/114439
+// { dg-do compile { target c++11 } }
+
+struct S {
+  int *list = arr;
+  __extension__ int arr[];
+};
+
+struct R {
+  int *list = arr;
+  int arr[2];
+};
+
+struct A {
+  A() {}
+  S s[2]{};
+};
+
+struct A2 {
+  A2() {}
+  S s[2]{ {}, {} };
+};
+
+struct B {
+  B() {}
+  R r[2]{};
+};
+
+struct B2 {
+  B2() {}
+  R r[2]{ {}, {} };
+};
+
+struct S1 { S1(); };
+struct S2 {
+  S2() {}
+  S1 a[1] {};
+};


[gcc r14-9622] c++: direct-init of an array of class type [PR59465]

2024-03-22 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:d1d8fd2884b44598d80de1038b086eec41519d4b

commit r14-9622-gd1d8fd2884b44598d80de1038b086eec41519d4b
Author: Marek Polacek 
Date:   Thu Feb 22 18:49:08 2024 -0500

c++: direct-init of an array of class type [PR59465]

...from another array in a mem-initializer should not be accepted.

We already reject

  struct string {} a[1];
  string x[1](a);

but

  struct pair {
string s[1];
pair() : s(a) {}
  };

is wrongly accepted.

It started to be accepted with r0-110915-ga034826198b771:

which was supposed to be a cleanup, not a deliberate change to start
accepting the code.  The build_vec_init_expr code was added in r165976:
.

It appears that we do the magic copy array when we have a defaulted
constructor and we generate code for its mem-initializer which
initializes an array.  I also see that we go that path for compound
literals.  So when initializing an array member, we can limit building
up a VEC_INIT_EXPR to those special cases.

PR c++/59465

gcc/cp/ChangeLog:

* init.cc (can_init_array_with_p): New.
(perform_member_init): Check it.

gcc/testsuite/ChangeLog:

* g++.dg/init/array62.C: New test.
* g++.dg/init/array63.C: New test.
* g++.dg/init/array64.C: New test.

Diff:
---
 gcc/cp/init.cc  | 31 ---
 gcc/testsuite/g++.dg/init/array62.C | 19 +++
 gcc/testsuite/g++.dg/init/array63.C | 13 +
 gcc/testsuite/g++.dg/init/array64.C | 22 ++
 4 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index d2586fad86b..dbd37d47cbf 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -934,6 +934,33 @@ find_uninit_fields (tree *t, hash_set 
*uninitialized, tree member)
 }
 }
 
+/* Return true if it's OK to initialize an array TYPE from INIT.  Mere mortals
+   can't copy arrays, but the compiler can do so with a VEC_INIT_EXPR in
+   certain cases.  */
+
+static bool
+can_init_array_with_p (tree type, tree init)
+{
+  if (!init)
+/* Value-init, OK.  */
+return true;
+  if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (init)))
+return false;
+  /* We're called from synthesize_method, and we're processing the
+ mem-initializers of a constructor.  */
+  if (DECL_DEFAULTED_FN (current_function_decl))
+return true;
+  /* As an extension, we allow copying from a compound literal.  */
+  if (TREE_CODE (init) == TARGET_EXPR)
+{
+  init = TARGET_EXPR_INITIAL (init);
+  if (TREE_CODE (init) == CONSTRUCTOR)
+   return CONSTRUCTOR_C99_COMPOUND_LITERAL (init);
+}
+
+  return false;
+}
+
 /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
arguments.  If TREE_LIST is void_type_node, an empty initializer
list was given; if NULL_TREE no initializer was given.  UNINITIALIZED
@@ -1087,9 +1114,7 @@ perform_member_init (tree member, tree init, 
hash_set &uninitialized)
 {
   if (TREE_CODE (type) == ARRAY_TYPE)
{
- if (init == NULL_TREE
- || same_type_ignoring_top_level_qualifiers_p (type,
-   TREE_TYPE (init)))
+ if (can_init_array_with_p (type, init))
{
  if (TYPE_DOMAIN (type) && TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
{
diff --git a/gcc/testsuite/g++.dg/init/array62.C 
b/gcc/testsuite/g++.dg/init/array62.C
new file mode 100644
index 000..2a786a36e4e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array62.C
@@ -0,0 +1,19 @@
+// PR c++/59465
+// { dg-do compile }
+
+struct string {} a[1];
+struct pair {
+  string s[1];
+  pair() : s(a) {} // { dg-error "invalid initializer for array member" }
+};
+
+struct S {
+  char s[10];
+  S() : s("aaa") {}
+};
+
+void
+g ()
+{
+  string x[1](a); // { dg-error "array must be initialized" }
+}
diff --git a/gcc/testsuite/g++.dg/init/array63.C 
b/gcc/testsuite/g++.dg/init/array63.C
new file mode 100644
index 000..57e98056168
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array63.C
@@ -0,0 +1,13 @@
+// PR c++/59465
+// { dg-do compile }
+
+struct I {
+const bool b;
+};
+struct O {
+I a[2];
+static I const data[2];
+O() : a(data){}  // { dg-error "invalid initializer for array member" }
+};
+
+I const O::data[2] = {true, false};
diff --git a/gcc/testsuite/g++.dg/init/array64.C 
b/gcc/testsuite/g++.dg/init/array64.C
new file mode 100644
index 000..e0afdfab39a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array64.C
@@ -0,0 +1,22 @@
+// PR c++/59465
+// { dg-do compile }
+
+static const int my_size = 10;
+
+class UserType
+{
+public:
+  UserType(): f_(){}
+pr

[gcc r14-9596] c++: explicit inst of template method not generated [PR110323]

2024-03-21 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:081f8937cb82da311c224da04b0c6cbd57a8fb5d

commit r14-9596-g081f8937cb82da311c224da04b0c6cbd57a8fb5d
Author: Marek Polacek 
Date:   Thu Mar 7 20:41:23 2024 -0500

c++: explicit inst of template method not generated [PR110323]

Consider

  constexpr int VAL = 1;
  struct foo {
  template 
  void bar(typename std::conditional::type arg) { }
  };
  template void foo::bar<1>(int arg);

where we since r11-291 fail to emit the code for the explicit
instantiation.  That's because cp_walk_subtrees/TYPENAME_TYPE now
walks TYPE_CONTEXT ('conditional' here) as well, and in a template
finds the B==VAL template argument.  VAL is constexpr, which implies const,
which in the global scope implies static.  constrain_visibility_for_template
then makes "struct conditional<(B == VAL), int, float>" non-TREE_PUBLIC.
Then symtab_node::needed_p checks TREE_PUBLIC, sees it's 0, and we don't
emit any code.

I thought the fix would be some ODR-esque check to not consider
constexpr variables/fns that are used just for their value.  But
it turned out to be tricky.  For instance, we can't skip
determine_visibility in a template; we can't even skip it for value-dep
expressions.  For example, no-linkage-expr1.C has

  using P = struct {}*;
  template 
  void f(int(*)[((P)0, N)]) {}

where ((P)0, N) is value-dep, but N is not relevant here: we have to
ferret out the anonymous type.  When instantiating, it's already gone.

This patch uses decl_constant_var_p.  This is to implement (an
approximation) [basic.def.odr]#14.5.1 and [basic.def.odr]#5.2.

PR c++/110323

gcc/cp/ChangeLog:

* decl2.cc (min_vis_expr_r) : Do nothing for
decl_constant_var_p VAR_DECLs.

gcc/testsuite/ChangeLog:

* g++.dg/template/explicit-instantiation6.C: New test.
* g++.dg/template/explicit-instantiation7.C: New test.

Diff:
---
 gcc/cp/decl2.cc|  7 +++-
 .../g++.dg/template/explicit-instantiation6.C  | 43 ++
 .../g++.dg/template/explicit-instantiation7.C  | 22 +++
 3 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 2562d8aeff6..1339f210dde 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2718,7 +2718,12 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void 
*data)
   /* Fall through.  */
 case VAR_DECL:
 case FUNCTION_DECL:
-  if (! TREE_PUBLIC (t))
+  if (decl_constant_var_p (t))
+   /* The ODR allows definitions in different TUs to refer to distinct
+  constant variables with internal or no linkage, so such a reference
+  shouldn't affect visibility (PR110323).  FIXME but only if the
+  lvalue-rvalue conversion is applied.  */;
+  else if (! TREE_PUBLIC (t))
tpvis = VISIBILITY_ANON;
   else
tpvis = DECL_VISIBILITY (t);
diff --git a/gcc/testsuite/g++.dg/template/explicit-instantiation6.C 
b/gcc/testsuite/g++.dg/template/explicit-instantiation6.C
new file mode 100644
index 000..8b77c9deb20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/explicit-instantiation6.C
@@ -0,0 +1,43 @@
+// PR c++/110323
+// { dg-do compile { target c++14 } }
+
+template
+struct conditional { using type = T; };
+
+template
+struct conditional { using type = F; };
+
+constexpr int VAL = 1;
+
+static constexpr int getval () { return 1; }
+
+template
+constexpr int TVAL = 1;
+
+static struct S {
+  constexpr operator bool() { return true; }
+} s;
+
+struct foo {
+template 
+void bar(typename conditional::type arg) { }
+
+template 
+void qux(typename conditional, int, float>::type arg) { }
+
+template 
+void sox(typename conditional::type arg) 
{ }
+
+template 
+void nim(typename conditional::type arg) { }
+};
+
+template void foo::bar<1>(int arg);
+template void foo::qux<1>(int arg);
+template void foo::sox<1>(int arg);
+template void foo::nim<1>(int arg);
+
+// { dg-final { scan-assembler 
"_ZN3foo3barILi1EEEvN11conditionalIXeqT_L_ZL3VALEEifE4typeE" } }
+// { dg-final { scan-assembler 
"_ZN3foo3quxILi1EEEvN11conditionalIXeqT_L_Z4TVALIiEEEifE4typeE" } }
+// { dg-final { scan-assembler 
"_ZN3foo3soxILi1EEEvN11conditionalIXeqT_nxL_ZL3VALEEifE4typeE" } }
+// { dg-final { scan-assembler 
"_ZN3foo3nimILi1EEEvN11conditionalIXneT_szL_ZL3VALEEifE4typeE" } }
diff --git a/gcc/testsuite/g++.dg/template/explicit-instantiation7.C 
b/gcc/testsuite/g++.dg/template/explicit-instantiation7.C
new file mode 100644
index 000..9a870e808fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/explicit-instantiation7.C
@@ -0,0 +1,22 @@
+// PR c++/110323
+// { dg-do compile { target c++11 } }
+
+using P = struct { }*;
+using N = struct A { }*;
+
+template
+struct conditional { using type = T; };
+
+struct foo {
+te

[gcc r14-9558] testsuite: fix target for linkage-1.C

2024-03-19 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:7a6261332de58fd47283d694d8cd61ea7cdb324c

commit r14-9558-g7a6261332de58fd47283d694d8cd61ea7cdb324c
Author: Marek Polacek 
Date:   Tue Mar 19 17:15:38 2024 -0400

testsuite: fix target for linkage-1.C

This test fails in C++11 due to:

linkage-1.C:3:8: error: 'f' function uses 'auto' type specifier without 
trailing return type
3 | inline auto f() {
  |^~~~
linkage-1.C:3:8: note: deduced return type only available with '-std=c++14' 
or '-std=gnu++14'

Compile it in C++14 thus.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/linkage-1.C: Use target c++14.

Diff:
---
 gcc/testsuite/g++.dg/cpp2a/linkage-1.C | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/cpp2a/linkage-1.C 
b/gcc/testsuite/g++.dg/cpp2a/linkage-1.C
index 888ed6fa5b5..2b83ffe55b7 100644
--- a/gcc/testsuite/g++.dg/cpp2a/linkage-1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/linkage-1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++11 } }
+// { dg-do compile { target c++14 } }
 
 inline auto f() {
   struct A {};


[gcc r14-9364] c++: ICE with variable template and [[deprecated]] [PR110031]

2024-03-07 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:9f915684624413f96e1a5ffada398ccd1c533e38

commit r14-9364-g9f915684624413f96e1a5ffada398ccd1c533e38
Author: Marek Polacek 
Date:   Mon Mar 4 12:35:18 2024 -0500

c++: ICE with variable template and [[deprecated]] [PR110031]

lookup_and_finish_template_variable already has and uses the complain
parameter but it is not passing it down to mark_used so we got the
default tf_warning_or_error, which causes various problems when
lookup_and_finish_template_variable gets called with complain=tf_none.

PR c++/110031

gcc/cp/ChangeLog:

* pt.cc (lookup_and_finish_template_variable): Pass complain to
mark_used.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/inline-var11.C: New test.

Diff:
---
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1z/inline-var11.C | 32 +++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d73f6d93485..040ced45187 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10533,7 +10533,7 @@ lookup_and_finish_template_variable (tree templ, tree 
targs,
   if (var == error_mark_node)
 return error_mark_node;
   var = finish_template_variable (var, complain);
-  mark_used (var);
+  mark_used (var, complain);
   return var;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var11.C 
b/gcc/testsuite/g++.dg/cpp1z/inline-var11.C
new file mode 100644
index 000..d92911ed3a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inline-var11.C
@@ -0,0 +1,32 @@
+// PR c++/110031
+// { dg-do compile { target c++17 } }
+
+template 
+[[deprecated]]
+inline constexpr bool t = true ;
+
+template 
+struct enableif;
+
+template<>
+struct enableif
+{
+using y = int;
+};
+template 
+using enableif_t = typename enableif::y;
+
+template > = 0>   // { dg-warning "deprecated" }
+struct A {  A(T &&)  {  }};
+
+template 
+struct A {
+  A(T &&) = delete;
+  A() = delete;
+};
+
+int main(void)
+{
+  A a(5.3); // { dg-error "use of deleted function" }
+  return 0;
+}


[gcc r14-9339] c++: ICE with noexcept and local specialization [PR114114]

2024-03-06 Thread Marek Polacek via Gcc-cvs
https://gcc.gnu.org/g:dc6c3bfb59baab28b998e18396c06087b6d9b0ed

commit r14-9339-gdc6c3bfb59baab28b998e18396c06087b6d9b0ed
Author: Marek Polacek 
Date:   Tue Mar 5 13:33:10 2024 -0500

c++: ICE with noexcept and local specialization [PR114114]

Here we ICE because we call register_local_specialization while
local_specializations is null, so

  local_specializations->put ();

crashes on null this.  It's null since maybe_instantiate_noexcept calls
push_to_top_level which creates a new scope.  Normally, I would have
guessed that we need a new local_specialization_stack.  But here we're
dealing with an operand of a noexcept, which is an unevaluated operand,
and those aren't registered in the hash map.  maybe_instantiate_noexcept
wasn't signalling that it's substituting an unevaluated operand though.

PR c++/114114

gcc/cp/ChangeLog:

* pt.cc (maybe_instantiate_noexcept): Save/restore
cp_unevaluated_operand, c_inhibit_evaluation_warnings, and
cp_noexcept_operand around the tsubst_expr call.

gcc/testsuite/ChangeLog:

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

Diff:
---
 gcc/cp/pt.cc|  6 ++
 gcc/testsuite/g++.dg/cpp0x/noexcept84.C | 32 
 2 files changed, 38 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a6e6c804130..d73f6d93485 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -26879,10 +26879,16 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
  if (orig_fn)
++processing_template_decl;
 
+ ++cp_unevaluated_operand;
+ ++c_inhibit_evaluation_warnings;
+ ++cp_noexcept_operand;
  /* Do deferred instantiation of the noexcept-specifier.  */
  noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex),
  DEFERRED_NOEXCEPT_ARGS (noex),
  tf_warning_or_error, fn);
+ --cp_unevaluated_operand;
+ --c_inhibit_evaluation_warnings;
+ --cp_noexcept_operand;
 
  /* Build up the noexcept-specification.  */
  spec = build_noexcept_spec (noex, tf_warning_or_error);
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept84.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept84.C
new file mode 100644
index 000..06f33264f77
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept84.C
@@ -0,0 +1,32 @@
+// PR c++/114114
+// { dg-do compile { target c++11 } }
+
+template
+constexpr void
+test ()
+{
+  constexpr bool is_yes = B;
+  struct S {
+constexpr S() noexcept(is_yes) { }
+  };
+  S s;
+}
+
+constexpr bool foo() { return true; }
+
+template
+constexpr void
+test2 ()
+{
+  constexpr T (*pfn)() = &foo;
+  struct S {
+constexpr S() noexcept(pfn()) { }
+  };
+  S s;
+}
+
+int main()
+{
+  test();
+  test2();
+}