Re: [PATCH] c++: Optimize in maybe_clone_body aliases even when not at_eof [PR113208]

2024-05-10 Thread Jason Merrill

On 5/9/24 14:20, Jakub Jelinek wrote:

On Thu, Apr 25, 2024 at 11:30:48AM -0400, Jason Merrill wrote:

Hmm, maybe maybe_clone_body shouldn't clear DECL_SAVED_TREE for aliases, but
rather set it to some stub like void_node?

Though with all these changes, it's probably better to go with your first
patch for GCC 14 and delay this approach to 15.  Your v1 patch is OK for 14.


Ok, here is an updated patch, which sets DECL_SAVED_TREE to void_node for
the aliases together with reversion of the earlier committed patch.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-05-09  Jakub Jelinek  
Jason Merrill  

PR lto/113208
* cp-tree.h (maybe_optimize_cdtor): Remove.
* decl2.cc (tentative_decl_linkage): Call maybe_make_one_only
for implicit instantiations of maybe in charge ctors/dtors
declared inline.
(import_export_decl): Don't call maybe_optimize_cdtor.
(c_parse_final_cleanups): Formatting fixes.
* optimize.cc (can_alias_cdtor): Adjust condition, for
HAVE_COMDAT_GROUP && DECL_ONE_ONLY && DECL_WEAK return true even
if not DECL_INTERFACE_KNOWN.



--- gcc/cp/optimize.cc.jj   2024-04-25 20:33:30.771858912 +0200
+++ gcc/cp/optimize.cc  2024-05-09 17:10:23.920478922 +0200
@@ -220,10 +220,8 @@ can_alias_cdtor (tree fn)
gcc_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (fn));
/* Don't use aliases for weak/linkonce definitions unless we can put both
   symbols in the same COMDAT group.  */
-  return (DECL_INTERFACE_KNOWN (fn)
- && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn))
- && (!DECL_ONE_ONLY (fn)
- || (HAVE_COMDAT_GROUP && DECL_WEAK (fn;
+  return (DECL_WEAK (fn) ? (HAVE_COMDAT_GROUP && DECL_ONE_ONLY (fn))
+: (DECL_INTERFACE_KNOWN (fn) && !DECL_ONE_ONLY (fn)));


Hmm, would

(DECL_ONE_ONLY (fn) ? HAVE_COMDAT_GROUP
 : (DECL_INTERFACE_KNOWN (fn) && !DECL_WEAK (fn)))

make sense instead?  I don't think DECL_WEAK is necessary for COMDAT.

Jason



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

2024-05-10 Thread Jason Merrill

On 5/9/24 16:29, Patrick Palka wrote:

On Thu, 9 May 2024, Patrick Palka wrote:


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


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

PR c++/114994

gcc/cp/ChangeLog:

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

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 7c4ecf08c4b..1cd4992330c 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
code, int flags,
switch (code)
  {
  case MODIFY_EXPR:
-  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
+  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, complain);
  
  case INDIRECT_REF:

return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f82446331b3..505c04c6e52 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8264,6 +8264,9 @@ extern tree cp_build_c_cast   
(location_t, tree, tree,
  extern cp_expr build_x_modify_expr(location_t, tree,
 enum tree_code, tree,
 tree, tsubst_flags_t);
+extern tree cp_build_modify_expr   (location_t, tree,
+enum tree_code, tree,
+tree *, tsubst_flags_t);
  extern tree cp_build_modify_expr  (location_t, tree,
 enum tree_code, tree,
 tsubst_flags_t);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f3d52acaaac..bc71e534cf8 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21091,6 +21091,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
  /* This also suppresses -Wredundant-move.  */
  suppress_warning (ret, OPT_Wpessimizing_move);
+   if (warning_suppressed_p (t, OPT_Wparentheses))
+ suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
  }
  
  	RETURN (ret);

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b8c2bf8771f..e81f2b50d80 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -863,6 +863,17 @@ is_assignment_op_expr_p (tree t)
  return false;
  
tree fndecl = cp_get_callee_fndecl_nofold (call);

+  if (!fndecl
+  && processing_template_decl
+  && TREE_CODE (CALL_EXPR_FN (call)) == COMPONENT_REF)
+{
+  /* Also recognize (non-dependent) templated operator expressions that
+are represented as a direct call to operator=.
+TODO: maybe move this handling to cp_get_fndecl_from_callee for
+benefit of other callers.  */


Please.

Jason



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

2024-05-10 Thread Jason Merrill

On 5/9/24 16:23, Patrick Palka wrote:

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

-- >8 --

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

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

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

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

PR c++/114994

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe817..0b97b789aab 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,6 +275,13 @@ lvalue_kind (const_tree ref)
/* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
gcc_assert (processing_template_decl);
+  if (TREE_CODE (TREE_OPERAND (ref, 1)) == NOP_EXPR
+ && CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   /* As in the COND_EXPR case, but for non-dependent assignment
+  expressions created by build_x_modify_expr.  */
+   goto default_;


This seems overly specific, I'd think the same thing would apply to += 
and such?


Jason



Re: [PATCH v24 20/23] c++: Implement __is_invocable built-in trait

2024-05-10 Thread Jason Merrill

On 5/10/24 10:45, Ken Matsui wrote:

Fixed the incorrect if condition.  Could you please review this again?

-- >8 --

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 139 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 728 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 52d6841559c..8aa41f7147f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7340,6 +7340,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..bbe91a276e1 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,145 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree non_ref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (non_ref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (non_ref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = non_ref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  

Re: [PATCH v23 20/23] c++: Implement __is_invocable built-in trait

2024-05-10 Thread Jason Merrill

On 5/10/24 07:24, Ken Matsui wrote:

Fixed the reference to pointer to class case.  Ok for trunk?

-- >8 --

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 139 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 728 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 52d6841559c..8aa41f7147f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7340,6 +7340,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..7e66d67f5d9 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,145 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree non_ref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (non_ref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (non_ref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = non_ref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  if 

Re: [PATCH] c++, mingw, v2: Fix up types of dtor hooks to __cxa_{,thread_}atexit/__cxa_throw on mingw ia32 [PR114968]

2024-05-09 Thread Jason Merrill

On 5/9/24 14:46, Jakub Jelinek wrote:

On Thu, May 09, 2024 at 01:05:59PM -0400, Jason Merrill wrote:

I think I'd rather pass ob_parm to start_cleanup_fn, where it can also
replace the flag_use_cxa_atexit check in that function.


Good idea, changed in the following patch.


@@ -9998,7 +10004,8 @@ register_dtor_fn (tree decl)
   {
 /* We must convert CLEANUP to the type that "__cxa_atexit"
 expects.  */
-  cleanup = build_nop (get_atexit_fn_ptr_type (), cleanup);
+  cleanup = build_nop (ob_parm ? get_cxa_atexit_fn_ptr_type ()
+  : get_atexit_fn_ptr_type (), cleanup);


If we're (now) using the correct type to build the cleanup fn, this
conversion should be unnecessary.


This is the use_dtor case, where cleanup will have METHOD_TYPE, so
I think we need to cast.  But, we can cast always to
get_cxa_atexit_fn_ptr_type () type, because this is in use_dtor guarded code
and use_dtor is ob_parm && CLASS_TYPE_P (type), so when use_dtor is true,
ob_parm is also true.

Ok for trunk if it passes another bootstrap/regtest?


OK.


2024-05-09  Jakub Jelinek  

PR target/114968
gcc/
* target.def (use_atexit_for_cxa_atexit): Remove spurious space
from comment.
(adjust_cdtor_callabi_fntype): New cxx target hook.
* targhooks.h (default_cxx_adjust_cdtor_callabi_fntype): Declare.
* targhooks.cc (default_cxx_adjust_cdtor_callabi_fntype): New
function.
* doc/tm.texi.in (TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE): Add.
* doc/tm.texi: Regenerate.
* config/i386/i386.cc (ix86_cxx_adjust_cdtor_callabi_fntype): New
function.
(TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE): Redefine.
gcc/cp/
* cp-tree.h (atexit_fn_ptr_type_node, cleanup_type): Adjust macro
comments.
(get_cxa_atexit_fn_ptr_type): Declare.
* decl.cc (get_atexit_fn_ptr_type): Adjust function comment, only
build type for atexit argument.
(get_cxa_atexit_fn_ptr_type): New function.
(get_atexit_node): Call get_cxa_atexit_fn_ptr_type rather than
get_atexit_fn_ptr_type when using __cxa_atexit.
(get_thread_atexit_node): Call get_cxa_atexit_fn_ptr_type
rather than get_atexit_fn_ptr_type.
(start_cleanup_fn): Add ob_parm argument, call
get_cxa_atexit_fn_ptr_type or get_atexit_fn_ptr_type depending
on it and create PARM_DECL also based on that argument.
(register_dtor_fn): Adjust start_cleanup_fn caller, use
get_cxa_atexit_fn_ptr_type rather than get_atexit_fn_ptr_type
for use_dtor casts.
* except.cc (build_throw): Use get_cxa_atexit_fn_ptr_type ().

--- gcc/target.def.jj   2024-05-09 10:30:54.926503473 +0200
+++ gcc/target.def  2024-05-09 20:27:16.294780780 +0200
@@ -6498,7 +6498,7 @@ is in effect.  The default is to return
   hook_bool_void_false)
  
  /* Returns true if target may use atexit in the same manner as

-   __cxa_atexit  to register static destructors.  */
+   __cxa_atexit to register static destructors.  */
  DEFHOOK
  (use_atexit_for_cxa_atexit,
   "This hook returns true if the target @code{atexit} function can be used\n\
@@ -6509,6 +6509,17 @@ unloaded. The default is to return false
   bool, (void),
   hook_bool_void_false)
  
+/* Returns modified FUNCTION_TYPE for cdtor callabi.  */

+DEFHOOK
+(adjust_cdtor_callabi_fntype,
+ "This hook returns a possibly modified @code{FUNCTION_TYPE} for arguments\n\
+to @code{__cxa_atexit}, @code{__cxa_thread_atexit} or @code{__cxa_throw}\n\
+function pointers.  ABIs like mingw32 require special attributes to be added\n\
+to function types pointed to by arguments of these functions.\n\
+The default is to return the passed argument unmodified.",
+ tree, (tree fntype),
+ default_cxx_adjust_cdtor_callabi_fntype)
+
  DEFHOOK
  (adjust_class_at_definition,
  "@var{type} is a C++ class (i.e., RECORD_TYPE or UNION_TYPE) that has just\n\
--- gcc/targhooks.h.jj  2024-05-09 10:30:54.941503269 +0200
+++ gcc/targhooks.h 2024-05-09 20:27:16.315780505 +0200
@@ -65,6 +65,7 @@ extern machine_mode default_mode_for_suf
  
  extern tree default_cxx_guard_type (void);

  extern tree default_cxx_get_cookie_size (tree);
+extern tree default_cxx_adjust_cdtor_callabi_fntype (tree);
  
  extern bool hook_pass_by_reference_must_pass_in_stack

(cumulative_args_t, const function_arg_info &);
--- gcc/targhooks.cc.jj 2024-05-09 10:30:54.927503459 +0200
+++ gcc/targhooks.cc2024-05-09 20:27:16.338780204 +0200
@@ -329,6 +329,14 @@ default_cxx_get_cookie_size (tree type)
return cookie_size;
  }
  
+/* Returns modified FUNCTION_TYPE for cdtor callabi.  */

+
+tree
+default_cxx_adjust_cdtor_callabi_fntype (tree fntype)
+{
+  return fntype;
+}
+
  /* Return true if a parameter must be passed by reference.  This version
 of the TARGET_PASS_BY_REFERENCE hook uses just MUST_PASS_IN_STACK.  */
  
--- gcc/doc/tm.texi

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

2024-05-09 Thread Jason Merrill

On 5/9/24 15:28, Marek Polacek wrote:

On Thu, May 09, 2024 at 12:51:28PM -0400, Jason Merrill wrote:

On 5/9/24 12:03, Marek Polacek wrote:

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8787eabb9fd..46cf8a737fb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20569,6 +20569,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
TREE_SIDE_EFFECTS (r) = 0;
TREE_READONLY (r) = 1;
  }
+   copy_warning (r, t);
SET_EXPR_LOCATION (r, EXPR_LOCATION (t));


copy_warning is defined in terms of locations (as well as TREE_NO_WARNING),
so copying it before setting the location looks wrong.


Sigh.  Since 'r' had no location, this just set TREE_NO_WARNING, also fixing
this test.  But it's not what I meant to do.

Fixed below, thanks.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?


OK.


-- >8 --
-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.
---
  gcc/cp/pt.cc  |  1 +
  gcc/cp/semantics.cc   |  2 ++
  .../g++.dg/warn/Wsizeof-array-div3.C  | 27 +++
  3 files changed, 30 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8787eabb9fd..a7d9fcf930e 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 b8c2bf8771f..71520dcd4fa 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;
+}

base-commit: e02b5683e77c2b4317b23be72e43b6e6cc6c8e5b




Re: [PATCH] c++: ICE with reference NSDMI [PR114854]

2024-05-09 Thread Jason Merrill

On 5/9/24 12:04, Marek Polacek wrote:

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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 {};
   };

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 &) _EXPR }

where the TARGET_EXPR is no longer direct-initializing anything.


Seems like the problem is in convert_like_internal:


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;
  }


My patch for 50930 assumed that if a CONSTRUCTOR represents syntactic 
direct-initialization, a resulting TARGET_EXPR is itself the direct 
initializer, but that isn't the case here; the temporary is 
copy-initialized.


We could calculate direct-initializanity from cand->flags, but perhaps 
we can just stop trying to set TARGET_EXPR_DIRECT_INIT_P here at all? 
We don't do that for other list-initialization in ck_user, I don't know 
why I thought it was needed for {} specifically.  It doesn't seem to be 
needed for the 50930 testcase.


Jason



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

2024-05-09 Thread Jason Merrill

On 5/8/24 13:49, Patrick Palka wrote:

Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look
OK for trunk and perhaps 14?


OK for both.


-- >8 --

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

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

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

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

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

+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
if (parms)
  {
tree last = parms;
@@ -30417,7 +30418,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+   {
+ if (tree outer_targs = outer_template_args (f))
+   ci = tsubst_constraint_info (ci, 

Re: [PATCH] c++, mingw: Fix up types of dtor hooks to __cxa_{,thread_}atexit/__cxa_throw on mingw ia32 [PR114968]

2024-05-09 Thread Jason Merrill

On 5/9/24 05:01, Jakub Jelinek wrote:

Hi!

__cxa_atexit/__cxa_thread_atexit/__cxa_throw functions accept function
pointers to usually directly destructors rather than wrappers around
them.
Now, mingw ia32 uses implicitly __attribute__((thiscall)) calling
conventions for METHOD_TYPE (where the this pointer is passed in %ecx
register, the rest on the stack), so these functions use:
in config/os/mingw32/os_defines.h:
  #if defined (__i386__)
  #define _GLIBCXX_CDTOR_CALLABI __thiscall
  #endif
in libsupc++/cxxabi.h
__cxa_atexit(void (_GLIBCXX_CDTOR_CALLABI *)(void*), void*, void*) 
_GLIBCXX_NOTHROW;
__cxa_thread_atexit(void (_GLIBCXX_CDTOR_CALLABI *)(void*), void*, void *) 
_GLIBCXX_NOTHROW;
__cxa_throw(void*, std::type_info*, void (_GLIBCXX_CDTOR_CALLABI *) (void *))
__attribute__((__noreturn__));

Now, mingw for some weird reason uses
  #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
so it never actually uses __cxa_atexit, but does use __cxa_thread_atexit
and __cxa_throw.  Recent changes for modules result in more detailed
__cxa_*atexit/__cxa_throw prototypes precreated by the compiler, and if
that happens and one also includes , the compiler complains about
mismatches in the prototypes.

One thing is the missing thiscall attribute on the FUNCTION_TYPE, the
other problem is that all of atexit/__cxa_atexit/__cxa_thread_atexit
get function pointer types gets created by a single function,
get_atexit_fn_ptr_type (), which creates it depending on if atexit
or __cxa_atexit will be used as either void(*)(void) or void(*)(void *),
but when using atexit and __cxa_thread_atexit it uses the wrong function
type for __cxa_thread_atexit.

The following patch adds a target hook to add the thiscall attribute to the
function pointers, and splits the get_atexit_fn_ptr_type () function into
get_atexit_fn_ptr_type () and get_cxa_atexit_fn_ptr_type (), the former always
creates shared void(*)(void) type, the latter creates either
void(*)(void*) (on most targets) or void(__attribute__((thiscall))*)(void*)
(on mingw ia32).  So that we don't waiste another GTY global tree for it,
because cleanup_type used for the same purpose for __cxa_throw should be
the same, the code changes it to use that type too.

In register_dtor_fn then based on the decision whether to use atexit,
__cxa_atexit or __cxa_thread_atexit it picks the right function pointer
type, and also if it decides to emit a __tcf_* wrapper for the cleanup,
uses that type for that wrapper so that it agrees on calling convention.

Bootstrapped/regtested on x86_64-linux and i686-linux and Liu Hao tested
it on mingw32, ok for trunk?

2024-05-09  Jakub Jelinek  

PR target/114968
gcc/
* target.def (use_atexit_for_cxa_atexit): Remove spurious space
from comment.
(adjust_cdtor_callabi_fntype): New cxx target hook.
* targhooks.h (default_cxx_adjust_cdtor_callabi_fntype): Declare.
* targhooks.cc (default_cxx_adjust_cdtor_callabi_fntype): New
function.
* doc/tm.texi.in (TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE): Add.
* doc/tm.texi: Regenerate.
* config/i386/i386.cc (ix86_cxx_adjust_cdtor_callabi_fntype): New
function.
(TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE): Redefine.
gcc/cp/
* cp-tree.h (atexit_fn_ptr_type_node, cleanup_type): Adjust macro
comments.
(get_cxa_atexit_fn_ptr_type): Declare.
* decl.cc (get_atexit_fn_ptr_type): Adjust function comment, only
build type for atexit argument.
(get_cxa_atexit_fn_ptr_type): New function.
(get_atexit_node): Call get_cxa_atexit_fn_ptr_type rather than
get_atexit_fn_ptr_type when using __cxa_atexit.
(get_thread_atexit_node): Call get_cxa_atexit_fn_ptr_type
rather than get_atexit_fn_ptr_type.
(start_cleanup_fn): Add fntype argument, don't call
get_atexit_fn_ptr_type for it.
(register_dtor_fn): Adjust start_cleanup_fn caller, use
get_cxa_atexit_fn_ptr_type rather than get_atexit_fn_ptr_type
when ob_parm is true.
* except.cc (build_throw): Use get_cxa_atexit_fn_ptr_type ().

--- gcc/target.def.jj   2024-05-07 21:28:46.554394913 +0200
+++ gcc/target.def  2024-05-08 11:19:39.290798568 +0200
@@ -6498,7 +6498,7 @@ is in effect.  The default is to return
   hook_bool_void_false)
  
  /* Returns true if target may use atexit in the same manner as

-   __cxa_atexit  to register static destructors.  */
+   __cxa_atexit to register static destructors.  */
  DEFHOOK
  (use_atexit_for_cxa_atexit,
   "This hook returns true if the target @code{atexit} function can be used\n\
@@ -6509,6 +6509,17 @@ unloaded. The default is to return false
   bool, (void),
   hook_bool_void_false)
  
+/* Returns modified FUNCTION_TYPE for cdtor callabi.  */

+DEFHOOK
+(adjust_cdtor_callabi_fntype,
+ "This hook returns a possibly modified @code{FUNCTION_TYPE} for arguments\n\
+to @code{__cxa_atexit}, @code{__cxa_thread_atexit} or 

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

2024-05-09 Thread Jason Merrill

On 5/9/24 12:03, Marek Polacek wrote:

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
-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.
---
  gcc/cp/pt.cc  |  1 +
  gcc/cp/semantics.cc   |  2 ++
  .../g++.dg/warn/Wsizeof-array-div3.C  | 27 +++
  3 files changed, 30 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/warn/Wsizeof-array-div3.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8787eabb9fd..46cf8a737fb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20569,6 +20569,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
TREE_SIDE_EFFECTS (r) = 0;
TREE_READONLY (r) = 1;
  }
+   copy_warning (r, t);
SET_EXPR_LOCATION (r, EXPR_LOCATION (t));


copy_warning is defined in terms of locations (as well as 
TREE_NO_WARNING), so copying it before setting the location looks wrong.



  }
RETURN (r);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b8c2bf8771f..71520dcd4fa 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;
+}

base-commit: 2790195500ec523cad9c7292816540e2fc19f456




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

2024-05-09 Thread Jason Merrill

On 5/9/24 12:16, Marek Polacek wrote:

In GCC 14, I submitted a minimal fix for the "extra ; warning", pushed
in r14-8967.  That patch mentions a more complete patch for GCC 15.
This is the patch.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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.
---
  gcc/c-family/c.opt|  2 +-
  gcc/cp/parser.cc  | 94 +++
  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 | 29 ++
  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  | 18 
  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, 468 insertions(+), 19 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon1.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon10.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon11.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon12.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon13.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon14.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon15.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon16.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon17.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon2.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon3.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon4.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon5.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon6.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon7.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon8.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/semicolon9.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 403abc1f26e..fb34c3b7031 100644
--- a/gcc/c-family/c.opt
+++ 

Re: [PATCH v22 20/23] c++: Implement __is_invocable built-in trait

2024-05-09 Thread Jason Merrill

On 5/8/24 01:04, Ken Matsui wrote:

Fixed the reference_wrapper case.  I used non_ref_datum_type to avoid
potentially multiple build_trait_object calls.

-- >8 --

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 142 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 731 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 52d6841559c..8aa41f7147f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7340,6 +7340,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..1c3233ca5d7 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,148 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree non_ref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (non_ref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (non_ref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = non_ref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  

Re: [PATCH] c++: Implement C++26 P2893R3 - Variadic friends [PR114459]

2024-05-07 Thread Jason Merrill

On 5/3/24 12:35, Jakub Jelinek wrote:

Hi!

The following patch imeplements the C++26 P2893R3 - Variadic friends
paper.  The paper allows for the friend type declarations to specify
more than one friend type specifier and allows to specify ... at
the end of each.  The patch doesn't introduce tentative parsing of
friend-type-declaration non-terminal, but rather just extends existing
parsing where it is a friend declaration which ends with ; after the
declaration specifiers to the cases where it ends with ...; or , or ...,
In that case it pedwarns for cxx_dialect < cxx26, handles the ... and
if there is , continues in a loop to parse the further friend type
specifiers.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-05-03  Jakub Jelinek  

PR c++/114459
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine
__cpp_variadic_friend=202403L for C++26.
gcc/cp/
* parser.cc (cp_parser_member_declaration): Implement C++26
P2893R3 - Variadic friends.  Parse friend type declarations
with ... or with more than one friend type specifier.
* friend.cc (make_friend_class): Allow TYPE_PACK_EXPANSION.
* pt.cc (instantiate_class_template): Handle PACK_EXPANSION_P
in friend classes.
gcc/testsuite/
* g++.dg/cpp26/feat-cxx26.C (__cpp_variadic_friend): Add test.
* g++.dg/cpp26/variadic-friend1.C: New test.

--- gcc/c-family/c-cppbuiltin.cc.jj 2024-05-02 09:31:17.746298275 +0200
+++ gcc/c-family/c-cppbuiltin.cc2024-05-03 14:50:08.008242950 +0200
@@ -1093,6 +1093,7 @@ c_cpp_builtins (cpp_reader *pfile)
  cpp_define (pfile, "__cpp_placeholder_variables=202306L");
  cpp_define (pfile, "__cpp_structured_bindings=202403L");
  cpp_define (pfile, "__cpp_deleted_function=202403L");
+ cpp_define (pfile, "__cpp_variadic_friend=202403L");
}
if (flag_concepts)
  {
--- gcc/cp/parser.cc.jj 2024-05-03 09:43:47.781511477 +0200
+++ gcc/cp/parser.cc2024-05-03 13:26:38.208088017 +0200
@@ -28102,7 +28102,14 @@ cp_parser_member_declaration (cp_parser*
  goto out;
/* If there is no declarator, then the decl-specifier-seq should
   specify a type.  */


Let's mention C++26 variadic friends in this comment.  OK with that change.


-  if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+  if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+  || (cp_parser_friend_p (_specifiers)
+ && cxx_dialect >= cxx11
+ && (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+ || (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
+ && (cp_lexer_nth_token_is (parser->lexer, 2, CPP_SEMICOLON)
+ || cp_lexer_nth_token_is (parser->lexer, 2,
+   CPP_COMMA))
  {
/* If there was no decl-specifier-seq, and the next token is a
 `;', then we have something like:
@@ -28137,44 +28144,81 @@ cp_parser_member_declaration (cp_parser*
{
  /* If the `friend' keyword was present, the friend must
 be introduced with a class-key.  */
-  if (!declares_class_or_enum && cxx_dialect < cxx11)
-pedwarn (decl_spec_token_start->location, OPT_Wpedantic,
- "in C++03 a class-key must be used "
- "when declaring a friend");
-  /* In this case:
+ if (!declares_class_or_enum && cxx_dialect < cxx11)
+   pedwarn (decl_spec_token_start->location, OPT_Wpedantic,
+"in C++03 a class-key must be used "
+"when declaring a friend");
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+ && cxx_dialect < cxx26)
+   pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+OPT_Wc__26_extensions,
+"variadic friends or friend type declarations with "
+"multiple types only available with "
+"%<-std=c++2c%> or %<-std=gnu++2c%>");
+ location_t friend_loc = decl_specifiers.locations[ds_friend];
+ do
+   {
+ /* In this case:
  
-		template  struct A {

- friend struct A::B;
-   };
+template  struct A {
+  friend struct A::B;
+};
  
-		  A::B will be represented by a TYPENAME_TYPE, and

- therefore not recognized by check_tag_decl.  */
-  if (!type)
-{
-  type = decl_specifiers.type;
-  if (type && TREE_CODE (type) == TYPE_DECL)
-type = TREE_TYPE (type);
-}
-  /* Warn if an attribute cannot appear here, as per
- [dcl.attr.grammar]/5.  But not when 

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

2024-05-07 Thread Jason Merrill

On 5/7/24 01:35, Nathaniel Shead wrote:

On Thu, May 02, 2024 at 01:53:44PM -0400, Jason Merrill wrote:

On 5/2/24 10:40, Patrick Palka wrote:

On Thu, 2 May 2024, Nathaniel Shead wrote:


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

Another alternative would be to stream such !DECL_NAME temporaries with
a merge key of MK_unique rather than attempting to find the matching
(nonexistant) field of the class context.


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

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

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

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

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

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


Streaming by value sounds right, but as noted an important difference
between reference temps and others is DECL_NAME.  Perhaps the code Patrick
quotes could look at that as well as the context?

Jason



With my patch we would no longer go through the code that Patrick quotes
for class-scope temporaries that I can see; we would instead first hit
the following code in 'tree_node':


   if (DECL_P (t))
 {
   if (DECL_TEMPLATE_PARM_P (t))
{
  tpl_parm_value (t);
  goto done;
}

   if (!DECL_CONTEXT (t))
{
  /* There are a few cases of decls with no context.  We'll write
 these by value, but first assert they are cases we expect.  */
  gcc_checking_assert (ref == WK_normal);
  switch (TREE_CODE (t))
{
default: gcc_unreachable ();

case LABEL_DECL:
  /* CASE_LABEL_EXPRs contain uncontexted LABEL_DECLs.  */
  gcc_checking_assert (!DECL_NAME (t));
  break;

case VAR_DECL:
  /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs.  */
  gcc_checking_assert (!DECL_NAME (t)
   && DECL_ARTIFICIAL (t));
  break;

case PARM_DECL:
  /* REQUIRES_EXPRs have a tree list of uncontexted
 PARM_DECLS.  It'd be nice if they had a
 distinguishing flag to double check.  */
  break;
}
  goto by_value;
}
 }

  skip_normal:
   if (DECL_P (t) && !decl_node (t, ref))
 goto done;

   /* Otherwise by value */
  by_value:
   tree_value (t);


I think modifying what Patrick pointed out should only be necessary if
we maintain these nameless temporaries as having a class context; for
clarity, is that the direction you'd prefer me to go in to solve this?


I was thinking in this code that it seems fragile to require null 
DECL_CONTEXT to identify something produced by 
create_temporary_var/build_local_temp (which should really be merged).
We could even use is_local_temp instead of checking particular qualities 
directly.


But your patch is OK; please just add a comment to the 
make_temporary_var_for_ref_to_temp change indicating that you're setting 
DECL_CONTEXT to make the variable mergeable.


Thanks,
Jason



Re: [PATCH v21 20/23] c++: Implement __is_invocable built-in trait

2024-05-07 Thread Jason Merrill

On 5/3/24 16:52, Ken Matsui wrote:

Fixed datum reference problem.  Ok for trunk?

-- >8 --

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 137 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 726 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 52d6841559c..8aa41f7147f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7340,6 +7340,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..80791227a0a 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,143 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree deref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = deref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  if (is_ptrdatamem && 

Re: [PATCH v5 2/5] C++: Support clang compatible [[musttail]] (PR83324)

2024-05-06 Thread Jason Merrill

On 5/5/24 14:14, Andi Kleen wrote:

This patch implements a clang compatible [[musttail]] attribute for
returns.


Thanks.


musttail is useful as an alternative to computed goto for interpreters.
With computed goto the interpreter function usually ends up very big
which causes problems with register allocation and other per function
optimizations not scaling. With musttail the interpreter can be instead
written as a sequence of smaller functions that call each other. To
avoid unbounded stack growth this requires forcing a sibling call, which
this attribute does. It guarantees an error if the call cannot be tail
called which allows the programmer to fix it instead of risking a stack
overflow. Unlike computed goto it is also type-safe.

It turns out that David Malcolm had already implemented middle/backend
support for a musttail attribute back in 2016, but it wasn't exposed
to any frontend other than a special plugin.

This patch adds a [[gnu::musttail]] attribute for C++ that can be added
to return statements. The return statement must be a direct call
(it does not follow dependencies), which is similar to what clang
implements. It then uses the existing must tail infrastructure.

For compatibility it also detects clang::musttail

One problem is that tree-tailcall usually fails when optimization
is disabled, which implies the attribute only really works with
optimization on. But that seems to be a reasonable limitation.

Passes bootstrap and full test

PR83324

gcc/cp/ChangeLog:

* cp-tree.h (finish_return_stmt): Add musttail_p.
(check_return_expr): Dito.
* parser.cc (cp_parser_statement): Handle [[musttail]].
(cp_parser_std_attribute): Dito.
(cp_parser_init_statement): Dito.
(cp_parser_jump_statement): Dito.
* semantics.cc (finish_return_stmt): Dito.
* typeck.cc (check_return_expr): Handle musttail_p flag.
---
  gcc/cp/cp-tree.h|  4 ++--
  gcc/cp/parser.cc| 30 --
  gcc/cp/semantics.cc |  6 +++---
  gcc/cp/typeck.cc| 20 ++--
  4 files changed, 47 insertions(+), 13 deletions(-)

@@ -12734,9 +12734,27 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
 NULL_TREE, false);
  break;
  
+	case RID_RETURN:

+ {
+   bool musttail_p = false;
+   std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
+   if (lookup_attribute ("gnu", "musttail", std_attrs))
+ {
+   musttail_p = true;
+   std_attrs = remove_attribute ("gnu", "musttail", std_attrs);
+ }
+   // support this for compatibility
+   if (lookup_attribute ("clang", "musttail", std_attrs))
+ {
+   musttail_p = true;
+   std_attrs = remove_attribute ("clang", "musttail", std_attrs);
+ }
+   statement = cp_parser_jump_statement (parser, musttail_p);


It seems to me that if we were to pass _attrs to 
cp_parser_jump_statement, we could handle this entirely in that function 
rather than adding a flag to finish_return_stmt and check_return_stmt.



@@ -30189,7 +30207,7 @@ cp_parser_std_attribute (cp_parser *parser, tree 
attr_ns)
  /* Maybe we don't expect to see any arguments for this attribute.  */
  const attribute_spec *as
= lookup_attribute_spec (TREE_PURPOSE (attribute));
-if (as && as->max_length == 0)
+if ((as && as->max_length == 0) || is_attribute_p ("musttail", attr_id))


I'd prefer to add an attribute to the table, rather than special-case it 
here; apart from consistency, it seems likely that someone will later 
want to apply it to a function.


You need a template testcase; I expect it doesn't work in templates with 
the current patch.  It's probably enough to copy it in tsubst_expr where 
we currently propagate CALL_EXPR_OPERATOR_SYNTAX.


You also need a testcase where the function returns a class; in that 
case the call will often appear as AGGR_INIT_EXPR rather than CALL_EXPR, 
so you'll need to handle that as well.  And see the places that copy 
flags like CALL_EXPR_OPERATOR_SYNTAX between CALL_EXPR and AGGR_INIT_EXPR.


Jason



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

2024-05-06 Thread Jason Merrill

On 5/6/24 18:53, Patrick Palka wrote:

On Mon, 6 May 2024, Jason Merrill wrote:


On 5/3/24 07:17, Nathaniel Shead wrote:

On Thu, May 02, 2024 at 02:05:38PM -0400, Jason Merrill wrote:

On 5/1/24 21:34, Nathaniel Shead wrote:

On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:

On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:


On Wed, 1 May 2024, Nathaniel Shead wrote:


Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk
(and
later 14.2)?  I don't think making it a GTY root is necessary but
I felt
perhaps better to be safe than sorry.

Potentially another approach would be to use DECL_UID instead like
how
entity_map does; would that be preferable?

-- >8 --

I got notified by Linaro CI and by checking testresults that there
seems
to be some occasional failures in tpl-friend-4_b.C on some
architectures
and standards modes since r15-59-gb5f6a56940e708.  I haven't been
able
to reproduce but looking at the backtrace I suspect the issue is
that
we're adding to the 'imported_temploid_friend' map a decl that is
ultimately discarded, which then has its address reused by a later
decl
causing a failure in the assert in 'set_originating_module'.

This patch attempts to fix the issue in two ways: by ensuring that
we
only store the decl if we know it's a new decl (and hence won't be
discarded), and by making the imported_temploid_friends map a GTY
root
so that even if the decl does get discarded later the address
isn't
reused.

gcc/cp/ChangeLog:

* module.cc (imported_temploid_friends): Mark GTY, and...
(init_modules): ...allocate from GGC.
(trees_in::decl_value): Only write to
imported_temploid_friends
for new decls.

Signed-off-by: Nathaniel Shead 
---
gcc/cp/module.cc | 7 ---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 5b8ff5bc483..37d38bb9654 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
   need to be attached to the same module as the temploid.
This maps
   these decls to the temploid they are instantiated them, as
there is
   no other easy way to get this information.  */
-static hash_map *imported_temploid_friends;
+static GTY(()) hash_map *imported_temploid_friends;
//
/* Tree streaming.   The tree streaming is very specific to the
tree
@@ -8327,7 +8327,8 @@ trees_in::decl_value ()
  if (TREE_CODE (inner) == FUNCTION_DECL
  || TREE_CODE (inner) == TYPE_DECL)
if (tree owner = tree_node ())
-  imported_temploid_friends->put (decl, owner);
+  if (is_new)
+   imported_temploid_friends->put (decl, owner);


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

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

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


Could we instead move the call to propagate_defining_module down a few
lines, after the pushdecl?


Doing that for tsubst_friend_class seems to work OK with my current test
cases, but for tsubst_friend_function doing so causes ICEs in
'module_may_redeclare' within duplicate_decls because the function is
already marked as attached but the originating module information hasn't
been setup yet.


It's unfortunate that we need to add a hash table entry in order to make it
through duplicate_decls, at which point it becomes dead.  Ah, well.


I suppose with tsubst_friend_class it works though because we can't ever
take the pushdecl branch if an existing type exists that we would call
duplicate_decls on.


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


It still means garbage entries in the hash_map, which is undesirable even
if
it doesn't cause the same kind of breakage.

Incidentally, decl_tree_map is preferable to hash_map when the
key is always a decl.


Ah thanks, didn't know about decl_tree_map.  I feel that I prefer using
DECL_UIDs explicitly here though; it's also consistent with the existing
usage in entity_map_t, and it looks like decl_tree_map is still perhaps
vulnerable to the original issue here (since DECL_UID is only used for
hashing and not for equality, it looks like?).

Though that said, 'decl_constraints' in constraints.cc seems to be u

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

2024-05-06 Thread Jason Merrill

On 5/3/24 11:26, Patrick Palka wrote:

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?


OK.


-- >8 --

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

gcc/cp/ChangeLog:

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

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8a3b5d80ba7..3f0dab79bcd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -622,33 +622,29 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
  
  struct norm_info : subst_info

  {
-  explicit norm_info (tsubst_flags_t cmp)
-: norm_info (NULL_TREE, cmp)
+  explicit norm_info (bool diag)
+: norm_info (NULL_TREE, diag)
{}
  
/* Construct a top-level context for DECL.  */
  
-  norm_info (tree in_decl, tsubst_flags_t complain)

-: subst_info (tf_warning_or_error | complain, in_decl)
+  norm_info (tree in_decl, bool diag)
+: subst_info (tf_warning_or_error, in_decl),
+  generate_diagnostics (diag)
{
  if (in_decl)
{
initial_parms = DECL_TEMPLATE_PARMS (in_decl);
-   if (generate_diagnostics ())
+   if (generate_diagnostics)
  context = build_tree_list (NULL_TREE, in_decl);
}
  else
initial_parms = current_template_parms;
}
  
-  bool generate_diagnostics() const

-  {
-return complain & tf_norm;
-  }
-
void update_context(tree expr, tree args)
{
-if (generate_diagnostics ())
+if (generate_diagnostics)
{
tree map = build_parameter_mapping (expr, args, ctx_parms ());
context = tree_cons (map, expr, context);
@@ -679,6 +675,10 @@ struct norm_info : subst_info
   template parameters of ORIG_DECL.  */
  
tree initial_parms = NULL_TREE;

+
+  /* Whether to build diagnostic information during normalization.  */
+
+  bool generate_diagnostics;
  };
  
  static tree normalize_expression (tree, tree, norm_info);

@@ -693,7 +693,7 @@ normalize_logical_operation (tree t, tree args, tree_code 
c, norm_info info)
tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
  
/* Build a new info object for the constraint.  */

-  tree ci = info.generate_diagnostics()
+  tree ci = info.generate_diagnostics
  ? build_tree_list (t, info.context)
  : NULL_TREE;
  
@@ -777,7 +777,7 @@ normalize_concept_check (tree check, tree args, norm_info info)

if (!norm_cache)
  norm_cache = hash_table::create_ggc (31);
norm_entry *entry = nullptr;
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
  {
/* Cache the normal form of the substituted concept-id (when not
 diagnosing).  */
@@ -831,7 +831,7 @@ normalize_atom (tree t, tree args, norm_info info)
if (info.in_decl && concept_definition_p (info.in_decl))
  ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
  
-  if (!info.generate_diagnostics ())

+  if (!info.generate_diagnostics)
  {
/* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
 later can cheaply compare two atoms using just pointer equality.  */
@@ -910,7 +910,7 @@ get_normalized_constraints_from_info (tree ci, tree 
in_decl, bool diag = false)
  
/* Substitution errors during normalization are fatal.  */

++processing_template_decl;
-  norm_info info (in_decl, diag ? tf_norm : tf_none);
+  norm_info info (in_decl, diag);
tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci), info);
--processing_template_decl;
  
@@ -1012,7 +1012,7 @@ normalize_concept_definition (tree tmpl, bool diag)

gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
++processing_template_decl;
-  norm_info info (tmpl, diag ? tf_norm : tf_none);
+  norm_info info (tmpl, diag);
tree norm = get_normalized_constraints (def, info);
--processing_template_decl;
  
@@ -1035,7 +1035,7 @@ normalize_constraint_expression (tree expr, norm_info info)

if (!expr || expr == error_mark_node)
  

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

2024-05-06 Thread Jason Merrill

On 5/3/24 07:17, Nathaniel Shead wrote:

On Thu, May 02, 2024 at 02:05:38PM -0400, Jason Merrill wrote:

On 5/1/24 21:34, Nathaniel Shead wrote:

On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:

On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:


On Wed, 1 May 2024, Nathaniel Shead wrote:


Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk (and
later 14.2)?  I don't think making it a GTY root is necessary but I felt
perhaps better to be safe than sorry.

Potentially another approach would be to use DECL_UID instead like how
entity_map does; would that be preferable?

-- >8 --

I got notified by Linaro CI and by checking testresults that there seems
to be some occasional failures in tpl-friend-4_b.C on some architectures
and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
to reproduce but looking at the backtrace I suspect the issue is that
we're adding to the 'imported_temploid_friend' map a decl that is
ultimately discarded, which then has its address reused by a later decl
causing a failure in the assert in 'set_originating_module'.

This patch attempts to fix the issue in two ways: by ensuring that we
only store the decl if we know it's a new decl (and hence won't be
discarded), and by making the imported_temploid_friends map a GTY root
so that even if the decl does get discarded later the address isn't
reused.

gcc/cp/ChangeLog:

* module.cc (imported_temploid_friends): Mark GTY, and...
(init_modules): ...allocate from GGC.
(trees_in::decl_value): Only write to imported_temploid_friends
for new decls.

Signed-off-by: Nathaniel Shead 
---
   gcc/cp/module.cc | 7 ---
   1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 5b8ff5bc483..37d38bb9654 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
  need to be attached to the same module as the temploid.  This maps
  these decls to the temploid they are instantiated them, as there is
  no other easy way to get this information.  */
-static hash_map *imported_temploid_friends;
+static GTY(()) hash_map *imported_temploid_friends;
   //
   /* Tree streaming.   The tree streaming is very specific to the tree
@@ -8327,7 +8327,8 @@ trees_in::decl_value ()
 if (TREE_CODE (inner) == FUNCTION_DECL
 || TREE_CODE (inner) == TYPE_DECL)
   if (tree owner = tree_node ())
-  imported_temploid_friends->put (decl, owner);
+  if (is_new)
+   imported_temploid_friends->put (decl, owner);


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

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

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


Could we instead move the call to propagate_defining_module down a few
lines, after the pushdecl?


Doing that for tsubst_friend_class seems to work OK with my current test
cases, but for tsubst_friend_function doing so causes ICEs in
'module_may_redeclare' within duplicate_decls because the function is
already marked as attached but the originating module information hasn't
been setup yet.


It's unfortunate that we need to add a hash table entry in order to make 
it through duplicate_decls, at which point it becomes dead.  Ah, well.



I suppose with tsubst_friend_class it works though because we can't ever
take the pushdecl branch if an existing type exists that we would call
duplicate_decls on.


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


It still means garbage entries in the hash_map, which is undesirable even if
it doesn't cause the same kind of breakage.

Incidentally, decl_tree_map is preferable to hash_map when the
key is always a decl.


Ah thanks, didn't know about decl_tree_map.  I feel that I prefer using
DECL_UIDs explicitly here though; it's also consistent with the existing
usage in entity_map_t, and it looks like decl_tree_map is still perhaps
vulnerable to the original issue here (since DECL_UID is only used for
hashing and not for equality, it looks like?).

Though that said, 'decl_constraints' in constraints.cc seems to be using
it fine (well, with a GTY marking) by using 'remove_constraints' within
duplicate_de

Re: [PATCH] c++: Allow IS_FAKE_BASE_TYPE for union types [PR114954]

2024-05-06 Thread Jason Merrill

On 5/6/24 02:32, Nathaniel Shead wrote:

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

-- >8 --

In some circumstances, unions can also have an __as_base type;


Hmm, even though unions can't be bases I guess that is needed for 
something like


union U {
  int i;
private:
  char c[5];
};

struct A {
  [[no_unique_address]] U u;
  char d;
};

static_assert (sizeof (A) == sizeof (U));

The patch is OK.


we need to make sure that IS_FAKE_BASE_TYPE correctly recognises this.

PR c++/114954

gcc/cp/ChangeLog:

* cp-tree.h (IS_FAKE_BASE_TYPE): Also apply to unions.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr114954.C: New test.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/cp-tree.h|  2 +-
  gcc/testsuite/g++.dg/modules/pr114954.C | 14 ++
  2 files changed, 15 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/modules/pr114954.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 933504b4821..fa24217eb2b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2616,7 +2616,7 @@ struct GTY(()) lang_type {
  
  /* True iff NODE is the CLASSTYPE_AS_BASE version of some type.  */

  #define IS_FAKE_BASE_TYPE(NODE)   \
-  (TREE_CODE (NODE) == RECORD_TYPE \
+  (RECORD_OR_UNION_TYPE_P (NODE)   \
 && TYPE_CONTEXT (NODE) && CLASS_TYPE_P (TYPE_CONTEXT (NODE))   \
 && CLASSTYPE_AS_BASE (TYPE_CONTEXT (NODE)) == (NODE))
  
diff --git a/gcc/testsuite/g++.dg/modules/pr114954.C b/gcc/testsuite/g++.dg/modules/pr114954.C

new file mode 100644
index 000..a9787140808
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114954.C
@@ -0,0 +1,14 @@
+// PR c++/114954
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi main }
+
+export module main;
+
+template 
+union U {
+private:
+  char a[N + 1];
+  int b;
+};
+
+U<4> p;




Re: [PATCH] Fix PR c++/105760: ICE in build_deduction_guide for invalid template

2024-05-06 Thread Jason Merrill

On 5/6/24 09:20, Simon Martin wrote:

Hi,

We currently ICE upon the following invalid snippet because we fail to 
properly handle tsubst_arg_types returning error_mark_node in 
build_deduction_guide.


== cut ==
template
struct A { A(Ts...); };
A a;
== cut ==

This patch fixes this, and has been successfully tested on 
x86_64-pc-linux-gnu. OK for trunk?


OK, thanks.


Thanks!

-- Simon

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a78d9d546d6..9acef73e7ac 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2024-05-06  Simon Martin  
+
+   PR c++/105760
+   * pt.c (build_deduction_guide): Check for error_mark_node
+   result from tsubst_arg_types.
+
  2024-05-03  Jason Merrill  

     PR c++/114935
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d68d688016d..da5d9b8a665 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30018,6 +30018,8 @@ build_deduction_guide (tree type, tree ctor, 
tree outer_args, tsubst_flags_t com

  references to members of an unknown specialization.  */
   cp_evaluated ev;
   fparms = tsubst_arg_types (fparms, targs, NULL_TREE, 
complain, ctor);

+ if (fparms == error_mark_node)
+   ok = false;
   fargs = tsubst (fargs, targs, complain, ctor);
   if (ci)
     {
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 03c88bbed07..8c606a8fb4f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2024-05-06  Simon Martin  
+
+   PR c++/105760
+   * g++.dg/parse/error66.C: New test.
+
  2024-05-05  Harald Anlauf  

     PR fortran/114827
diff --git a/gcc/testsuite/g++.dg/parse/error66.C 
b/gcc/testsuite/g++.dg/parse/error66.C

new file mode 100644
index 000..82f4b8b8a53
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/error66.C
@@ -0,0 +1,6 @@
+// PR c++/105760
+// { dg-do compile { target c++17 } }
+
+template // { dg-error "must be at the end of the 
template parameter list" }

+struct A { A(Ts...); };
+A a;





Re: [PATCH] contrib/gcc-changelog/git_check_commit.py: Implement --num-commits

2024-05-06 Thread Jason Merrill

On 5/6/24 09:25, Ken Matsui wrote:

On Thu, Mar 14, 2024 at 12:57 AM Ken Matsui  wrote:


On Fri, Mar 8, 2024 at 8:42 AM Patrick Palka  wrote:


On Wed, 28 Feb 2024, Ken Matsui wrote:


This patch implements a --num-commits (-n) flag for shorthand for
the range of hash~N..hash commits.


Ping.


Ping.  Ok for trunk?


OK.



contrib/ChangeLog:

   * gcc-changelog/git_check_commit.py: Implement --num-commits.


LGTM



Signed-off-by: Ken Matsui 
---
  contrib/gcc-changelog/git_check_commit.py | 15 +++
  1 file changed, 15 insertions(+)

diff --git a/contrib/gcc-changelog/git_check_commit.py 
b/contrib/gcc-changelog/git_check_commit.py
index 8cca9f439a5..22e032e8b38 100755
--- a/contrib/gcc-changelog/git_check_commit.py
+++ b/contrib/gcc-changelog/git_check_commit.py
@@ -22,6 +22,12 @@ import argparse

  from git_repository import parse_git_revisions

+def nonzero_uint(value):
+ivalue = int(value)
+if ivalue <= 0:
+raise argparse.ArgumentTypeError('%s is not a non-zero positive 
integer' % value)
+return ivalue
+
  parser = argparse.ArgumentParser(description='Check git ChangeLog format '
   'of a commit')
  parser.add_argument('revisions', default='HEAD', nargs='?',
@@ -33,8 +39,17 @@ parser.add_argument('-p', '--print-changelog', 
action='store_true',
  help='Print final changelog entires')
  parser.add_argument('-v', '--verbose', action='store_true',
  help='Print verbose information')
+parser.add_argument('-n', '--num-commits', type=nonzero_uint, default=1,
+help='Number of commits to check (i.e. shorthand for '
+'hash~N..hash)')
  args = parser.parse_args()

+if args.num_commits > 1:
+if '..' in args.revisions:
+print('ERR: --num-commits and range of revisions are mutually 
exclusive')
+exit(1)
+args.revisions = '{0}~{1}..{0}'.format(args.revisions, args.num_commits)
+
  retval = 0
  for git_commit in parse_git_revisions(args.git_path, args.revisions):
  res = 'OK' if git_commit.success else 'FAILED'
--
2.44.0










[pushed] c++: initializer_list and EH [PR114935]

2024-05-03 Thread Jason Merrill
Tested x86_64-pc-linux-gnu, applying to trunk and 14.

-- 8< --

When we initialize an array of a type with a non-trivial destructor, such as
the backing array for the initializer_list, we have a cleanup to destroy any
constructed elements if a later constructor throws.  When the array being
created is a variable, the end of that EH region naturally coincides with
the beginning of the EH region for the cleanup for the variable as a whole.

But if the array is a temporary, or a subobject of one, the array cleanup
region lasts for the rest of the full-expression, along with the normal
cleanup for the TARGET_EXPR.  As a result, when tata throws we clean it up
twice.  Before r14-1705 we avoided this by disabling the array cleanup in
split_nonconstant_init, but after that we don't go through
split_nonconstant_init, so let's handle it in cp_genericize_target_expr.

PR c++/114935

gcc/cp/ChangeLog:

* cp-gimplify.cc (cp_genericize_init): Add flags parm.
(cp_genericize_init_expr): Pass nullptr.
(cp_genericize_target_expr): Handle cleanup flags.
* typeck2.cc (build_disable_temp_cleanup): Factor out of...
(split_nonconstant_init): ...here.
* cp-tree.h (build_disable_temp_cleanup): Declare.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/initlist-eh1.C: New test.
---
 gcc/cp/cp-tree.h  |  1 +
 gcc/cp/cp-gimplify.cc | 18 +---
 gcc/cp/typeck2.cc | 34 +--
 gcc/testsuite/g++.dg/cpp0x/initlist-eh1.C | 25 +
 4 files changed, 60 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-eh1.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1ba7054f8bc..52d6841559c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8411,6 +8411,7 @@ extern int abstract_virtuals_error
(abstract_class_use, tree,
 tsubst_flags_t = 
tf_warning_or_error);
 
 extern tree store_init_value   (tree, tree, vec**, int);
+extern tree build_disable_temp_cleanup (tree);
 extern tree split_nonconstant_init (tree, tree);
 extern bool check_narrowing(tree, tree, tsubst_flags_t,
 bool = false);
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index ab5acd18c99..5cbdf0ea498 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1063,11 +1063,11 @@ any_non_eliding_target_exprs (tree ctor)
the result.  */
 
 static void
-cp_genericize_init (tree *replace, tree from, tree to)
+cp_genericize_init (tree *replace, tree from, tree to, vec** flags)
 {
   tree init = NULL_TREE;
   if (TREE_CODE (from) == VEC_INIT_EXPR)
-init = expand_vec_init_expr (to, from, tf_warning_or_error);
+init = expand_vec_init_expr (to, from, tf_warning_or_error, flags);
   else if (TREE_CODE (from) == CONSTRUCTOR
   && TREE_SIDE_EFFECTS (from)
   && ((flag_exceptions
@@ -1101,7 +1101,7 @@ cp_genericize_init_expr (tree *stmt_p)
   /* Return gets confused if we clobber its INIT_EXPR this soon.  */
   && TREE_CODE (to) != RESULT_DECL)
 from = TARGET_EXPR_INITIAL (from);
-  cp_genericize_init (stmt_p, from, to);
+  cp_genericize_init (stmt_p, from, to, nullptr);
 }
 
 /* For a TARGET_EXPR, change the TARGET_EXPR_INITIAL.  We will need to use
@@ -1112,9 +1112,19 @@ cp_genericize_target_expr (tree *stmt_p)
 {
   iloc_sentinel ils = EXPR_LOCATION (*stmt_p);
   tree slot = TARGET_EXPR_SLOT (*stmt_p);
+  vec *flags = make_tree_vector ();
   cp_genericize_init (_EXPR_INITIAL (*stmt_p),
- TARGET_EXPR_INITIAL (*stmt_p), slot);
+ TARGET_EXPR_INITIAL (*stmt_p), slot, );
   gcc_assert (!DECL_INITIAL (slot));
+  for (tree f : flags)
+{
+  /* Once initialization is complete TARGET_EXPR_CLEANUP becomes active, so
+disable any subobject cleanups.  */
+  tree d = build_disable_temp_cleanup (f);
+  auto  = TARGET_EXPR_INITIAL (*stmt_p);
+  r = add_stmt_to_compound (r, d);
+}
+  release_tree_vector (flags);
 }
 
 /* Similar to if (target_expr_needs_replace) replace_decl, but TP is the
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 2985bfdf9ec..06bad4d3303 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -466,6 +466,25 @@ maybe_push_temp_cleanup (tree sub, vec **flags)
 }
 }
 
+/* F is something added to a cleanup flags vec by maybe_push_temp_cleanup or
+   build_vec_init.  Return the code to disable the cleanup it controls.  */
+
+tree
+build_disable_temp_cleanup (tree f)
+{
+  tree d = f;
+  tree i = boolean_false_node;
+  if (TREE_CODE (f) == TREE_LIST)
+{
+  /* To disable a build_vec_init cleanup, set
+iterator = maxindex.  */
+  d = TREE_PURPOSE (f);
+  i = TREE_VALUE (f);
+  ggc_free (f);
+}
+  return build2 (MODIFY_EXPR, TREE_TYPE (d), d, i);
+}
+
 

Re: [PATCH v20 23/26] c++: Implement __is_invocable built-in trait

2024-05-03 Thread Jason Merrill

On 5/2/24 23:25, Ken Matsui wrote:

Addressed Jason's review comments.  Ok for trunk?

-- >8 --

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 138 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 727 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1938ada0268..83dc20e1130 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7338,6 +7338,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..6bd590707b0 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,144 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree deref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = deref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  if (is_ptrdatamem && 

Re: [PATCH v18 23/26] c++: Implement __is_invocable built-in trait

2024-05-02 Thread Jason Merrill

On 5/2/24 16:47, Ken Matsui wrote:

On Thu, May 2, 2024 at 1:38 PM Jason Merrill  wrote:


On 5/2/24 16:12, Ken Matsui wrote:

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

   * cp-trait.def: Define __is_invocable.
   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
   * semantics.cc (trait_expr_value): Likewise.
   (finish_trait_expr): Likewise.
   * cp-tree.h (build_invoke): New function.
   * method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

   * g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
   * g++.dg/ext/is_invocable1.C: New test.
   * g++.dg/ext/is_invocable2.C: New test.
   * g++.dg/ext/is_invocable3.C: New test.
   * g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
   gcc/cp/constraint.cc |   6 +
   gcc/cp/cp-trait.def  |   1 +
   gcc/cp/cp-tree.h |   2 +
   gcc/cp/method.cc | 134 +
   gcc/cp/semantics.cc  |   5 +
   gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
   gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
   gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
   gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
   gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
   10 files changed, 723 insertions(+)
   create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
   create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
   create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
   create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
   case CPTK_IS_FUNCTION:
 inform (loc, "  %qT is not a function", t1);
 break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
   case CPTK_IS_LAYOUT_COMPATIBLE:
 inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
 break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
   DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
   DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
   DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
   DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
   DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
   DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1938ada0268..83dc20e1130 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7338,6 +7338,8 @@ extern tree get_copy_assign (tree);
   extern tree get_default_ctor(tree);
   extern tree get_dtor(tree, tsubst_flags_t);
   extern tree build_stub_object   (tree);
+extern tree build_invoke (tree, const_tree,
+  tsubst_flags_t);
   extern tree strip_inheriting_ctors  (tree);
   extern tree inherited_ctor_binfo(tree);
   extern bool base_ctor_omit_inherited_parms  (tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..faf932258e6 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,140 @@ build_trait_object (tree type)
 return build_stub_object (type);
   }

+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the
+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree deref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+

Re: [PATCH v19 23/26] c++: Implement __is_invocable built-in trait

2024-05-02 Thread Jason Merrill

On 5/2/24 22:09, Ken Matsui wrote:

This patch implements built-in trait for std::is_invocable.


Looks like this doesn't address my review comments on v18, only Marek's?


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 134 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 723 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1938ada0268..83dc20e1130 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7338,6 +7338,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..f6bca87282f 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,140 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree deref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = deref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  if 

Re: [PATCH v18 23/26] c++: Implement __is_invocable built-in trait

2024-05-02 Thread Jason Merrill

On 5/2/24 16:12, Ken Matsui wrote:

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

* cp-trait.def: Define __is_invocable.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
* cp-tree.h (build_invoke): New function.
* method.cc (build_invoke): New function.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
* g++.dg/ext/is_invocable1.C: New test.
* g++.dg/ext/is_invocable2.C: New test.
* g++.dg/ext/is_invocable3.C: New test.
* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |   6 +
  gcc/cp/cp-trait.def  |   1 +
  gcc/cp/cp-tree.h |   2 +
  gcc/cp/method.cc | 134 +
  gcc/cp/semantics.cc  |   5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
  10 files changed, 723 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28d7bf428e..6d14ef7dcc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3792,6 +3792,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_FUNCTION:
inform (loc, "  %qT is not a function", t1);
break;
+case CPTK_IS_INVOCABLE:
+  if (!t2)
+inform (loc, "  %qT is not invocable", t1);
+  else
+inform (loc, "  %qT is not invocable by %qE", t1, t2);
+  break;
  case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b1c875a6e7d..4e420d5390a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1938ada0268..83dc20e1130 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7338,6 +7338,8 @@ extern tree get_copy_assign   (tree);
  extern tree get_default_ctor  (tree);
  extern tree get_dtor  (tree, tsubst_flags_t);
  extern tree build_stub_object (tree);
+extern tree build_invoke   (tree, const_tree,
+tsubst_flags_t);
  extern tree strip_inheriting_ctors(tree);
  extern tree inherited_ctor_binfo  (tree);
  extern bool base_ctor_omit_inherited_parms(tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 08a3d34fb01..faf932258e6 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,140 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree deref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = deref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
+{
+  if (complain & 

Re: [PATCH v17 05/26] c++: Implement __is_pointer built-in trait

2024-05-02 Thread Jason Merrill

On 5/2/24 14:42, Ken Matsui wrote:

This patch implements built-in trait for std::is_pointer.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_pointer.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
Arrange the order lexically around __is_pointer.
* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 ++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  4 ++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  9 +++--
  gcc/testsuite/g++.dg/ext/is_pointer.C| 51 
  5 files changed, 65 insertions(+), 3 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d9caf546423..5a8aaa70fa6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_POD:
inform (loc, "  %qT is not a POD type", t1);
break;
+case CPTK_IS_POINTER:
+  inform (loc, "  %qT is not a pointer", t1);
+  break;
  case CPTK_IS_POLYMORPHIC:
inform (loc, "  %qT is not a polymorphic type", t1);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e9347453829..18e2d0f3480 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -82,6 +82,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, 
"__is_nothrow_convertible", 2)
  DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
  DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, 
"__is_pointer_interconvertible_base_of", 2)
  DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
  DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
  DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
  DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 351235a639a..86372ea0aba 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12586,6 +12586,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_POD:
return pod_type_p (type1);
  
+case CPTK_IS_POINTER:

+  return TYPE_PTR_P (type1);
+
  case CPTK_IS_POLYMORPHIC:
return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
  
@@ -12825,6 +12828,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_MEMBER_OBJECT_POINTER:
  case CPTK_IS_MEMBER_POINTER:
  case CPTK_IS_OBJECT:
+case CPTK_IS_POINTER:
  case CPTK_IS_REFERENCE:
  case CPTK_IS_SAME:
  case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b2e2f2f694d..4cbe6fe8cea 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,12 +119,15 @@
  #if !__has_builtin (__is_object)
  # error "__has_builtin (__is_object) failed"
  #endif
-#if !__has_builtin (__is_pointer_interconvertible_base_of)
-# error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
-#endif
  #if !__has_builtin (__is_pod)
  # error "__has_builtin (__is_pod) failed"
  #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
+#if !__has_builtin (__is_pointer_interconvertible_base_of)
+# error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
+#endif
  #if !__has_builtin (__is_polymorphic)
  # error "__has_builtin (__is_polymorphic) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C 
b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));

Re: [PATCH v17 01/26] c++: Implement __is_const built-in trait

2024-05-02 Thread Jason Merrill

On 5/2/24 14:42, Ken Matsui wrote:

This patch implements built-in trait for std::is_const.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_const.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 +++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  4 
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  gcc/testsuite/g++.dg/ext/is_const.C  | 20 
  5 files changed, 31 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8a3b5d80ba7..eaf17a50877 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3768,6 +3768,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_CLASS:
inform (loc, "  %qT is not a class", t1);
break;
+case CPTK_IS_CONST:
+  inform (loc, "  %qT is not a const type", t1);
+  break;
  case CPTK_IS_CONSTRUCTIBLE:
if (!t2)
  inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 394f006f20f..36faed9c0b3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -64,6 +64,7 @@ DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
  DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
  DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
  DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
  DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
  DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
  DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 2dde65a970b..fa7ba6a9edc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12530,6 +12530,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_CLASS:
return NON_UNION_CLASS_TYPE_P (type1);
  
+case CPTK_IS_CONST:

+  return CP_TYPE_CONST_P (type1);
+
  case CPTK_IS_CONSTRUCTIBLE:
return is_xible (INIT_EXPR, type1, type2);
  
@@ -12812,6 +12815,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_ARRAY:
  case CPTK_IS_BOUNDED_ARRAY:
  case CPTK_IS_CLASS:
+case CPTK_IS_CONST:
  case CPTK_IS_ENUM:
  case CPTK_IS_FUNCTION:
  case CPTK_IS_MEMBER_FUNCTION_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 02b4b4d745d..e3640faeb96 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -71,6 +71,9 @@
  #if !__has_builtin (__is_class)
  # error "__has_builtin (__is_class) failed"
  #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
  #if !__has_builtin (__is_constructible)
  # error "__has_builtin (__is_constructible) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C 
b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 000..8a0e8df72a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+using cClassType = const ClassType;
+using vClassType = volatile ClassType;
+using cvClassType = const volatile ClassType;
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));




Re: [PATCH v17 03/26] c++: Implement __is_volatile built-in trait

2024-05-02 Thread Jason Merrill

On 5/2/24 14:42, Ken Matsui wrote:

This patch implements built-in trait for std::is_volatile.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_volatile.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 +++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  4 
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  gcc/testsuite/g++.dg/ext/is_volatile.C   | 20 
  5 files changed, 31 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index eaf17a50877..d9caf546423 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3862,6 +3862,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_UNION:
inform (loc, "  %qT is not a union", t1);
break;
+case CPTK_IS_VOLATILE:
+  inform (loc, "  %qT is not a volatile type", t1);
+  break;
  case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
inform (loc, "  %qT is not a reference that binds to a temporary "
  "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 36faed9c0b3..e9347453829 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -92,6 +92,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, 
"__is_trivially_assignable", 2)
  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
"__reference_constructs_from_temporary", 2)
  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
"__reference_converts_from_temporary", 2)
  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index fa7ba6a9edc..351235a639a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12616,6 +12616,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_UNION:
return type_code1 == UNION_TYPE;
  
+case CPTK_IS_VOLATILE:

+  return CP_TYPE_VOLATILE_P (type1);
+
  case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
  
@@ -12826,6 +12829,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_SAME:
  case CPTK_IS_SCOPED_ENUM:
  case CPTK_IS_UNION:
+case CPTK_IS_VOLATILE:
break;
  
  case CPTK_IS_LAYOUT_COMPATIBLE:

diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e3640faeb96..b2e2f2f694d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -158,6 +158,9 @@
  #if !__has_builtin (__is_union)
  # error "__has_builtin (__is_union) failed"
  #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
  #if !__has_builtin (__reference_constructs_from_temporary)
  # error "__has_builtin (__reference_constructs_from_temporary) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C 
b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 000..80a1cfc880d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+using cClassType = const ClassType;
+using vClassType = volatile ClassType;
+using cvClassType = const volatile ClassType;
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));




Re: Trait built-in naming convention

2024-05-02 Thread Jason Merrill

On 5/2/24 15:36, Iain Sandoe wrote:




On 2 May 2024, at 20:30, Ken Matsui  wrote:

On Thu, May 2, 2024 at 10:54 AM Marek Polacek  wrote:


On Thu, May 02, 2024 at 08:37:53PM +0300, Ville Voutilainen wrote:

On Thu, 2 May 2024 at 20:25, Ken Matsui  wrote:

There was some discussion of how to name the built-ins back in
https://gcc.gnu.org/pipermail/gcc-patches/2007-March/thread.html#212171
but __builtin wasn't discussed.

Apparently this naming convention follows the MSVC precedent:
http://msdn2.microsoft.com/en-us/library/ms177194.aspx

I notice some discussion of this pattern around Clang adding various
built-ins in https://github.com/llvm/llvm-project/issues/61852
indicating that this is a policy based on precedent.

But I don't see any actual reason for this pattern other than that it's
what Paolo happened to do in 2007.

I'm not sure what the right way forward is.  Perhaps we're stuck with
the questionable choices of the past.



Hmm, I personally prefer the __builtin prefix.  However, it seems that
we need to reach a consensus across MSVC, Clang, and GCC.  Would this
be realistically possible?

Until then, I think it would be better to use __ for all built-in
traits.  What do you think?


My 0.02: __builtin as a prefix doesn't serve much of a purpose.
Consider __is_constructible. It doesn't add value
to make that __builtin_is_constructible. It's a built-in. Of course
it's a built-in. It's a compiler-implemented trait, and
this is just the intrinsic that implements it.


FWIW, I also like __is_constructible better than __builtin_is_constructible.


So, updating all existing built-in trait names does not seem
realistic.  I think there are two options:

1. As Jason said, we can use the same name as Clang does and otherwise
use __builtin.
2. Or we can simply use __ for all built-in traits to keep consistency
with other built-in traits.

Then, I feel option 2 would sound better since it's consistent across
all built-in type traits and it might confuse Clang when they
implement the same built-in.  Also, it would be easier for me to
implement built-in traits as I don't need to dig into the Clang code
every time I add a new one.


I agree, being consistent with the status-quo is valuable, some decisions
might have not be the best ones - but I think it would be terribly confusing
to mix __ and __builtin (it immediately makes the reader wonder whar the
difference is).


This seems to be the prevailing sentiment, so let's continue that way. 
Thanks for the input.


Jason


Most of the existing builtins for traits don't use a __builtin prefix.
Not in GCC, not in other compilers. They are indeed
just double-underscored versions of the traits. I think that's fine,
and consistent. There's precedent for this
across Embarcadero, Clang, MSVC, and GCC. See
https://clang.llvm.org/docs/LanguageExtensions.html

Yes, I know it's inconsistent with other built-ins that aren't C++
library traits. But the water's been flowing under
the bridge on that question for a while now.

I would also prefer at least considering mimicking a trait builtin's
name if some other compiler did it first. That's not a hill
to die on, we don't need to be 100% compatible including the naming,
but if we can, we should just use a name that was
chosen by someone else already. It's just nice to have the same name
if the traits do exactly the same thing. If they don't,
then it's good and in fact very good to give our trait a different name.



Marek






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

2024-05-02 Thread Jason Merrill

On 5/2/24 13:49, Patrick Palka wrote:

On Wed, 1 May 2024, Jason Merrill wrote:


On 5/1/24 13:40, Patrick Palka wrote:

On Wed, 1 May 2024, Jason Merrill wrote:


On 5/1/24 12:41, Patrick Palka wrote:

On Fri, 2 Feb 2024, Patrick Palka wrote:


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


Ping, now that stage 1 is open.


Thanks for the ping.  The earlier message isn't showing up in Thunderbird
for
some reason, though I see it in the gmail web interface...


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




@@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
ctx = TREE_VEC_ELT (ctx, 0);
  }
else
- ctx = tsubst_aggr_type (ctx, args,
- complain | tf_qualifying_scope,
- in_decl, /*entering_scope=*/1);
+ {
+   ctx = tsubst_scope (ctx, args, complain, in_decl);


Why is this one tsubst_scope while the others are all plain tsubst?


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


Do we want a tsubst_entering_scope function?


Which is just shorthand for tsubst + adjust_type_for_entering_scope?


That's what I was thinking.


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


I don't think we want that; having the distinction helps to avoid wrongly
looking up members of the primary template in contexts that shouldn't be able
to.


Makes sense.  How does the following look?

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

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1c3eef60c06..261d6b9f4c8 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -185,8 +185,6 @@ static int unify_pack_expansion (tree, tree, tree,
  static tree copy_template_args (tree);
  static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
  static void tsubst_each_template_parm_constraints (tree, tree, 
tsubst_flags_t);
-static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
-static tree tsubst_aggr_type_1 (tree, tree, tsubst_flags_t, tree, int);
  static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
  static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
  static bool check_specialization_scope (void);
@@ -9901,6 +9899,34 @@ maybe_get_template_decl_from_type_decl (tree decl)
  ? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl;
  }
  
+/* If TYPE is the generic implicit instantiation A, return the primary

+   template type A (which is suitable for entering into e.g. for name
+   lookup), otherwise return TYPE.  */


Maybe "e.g. for defining a member of A"

OK either way.


+
+tree
+adjust_type_for_entering_scope (tree type)
+{
+  if (CLASS_TYPE_P (type)
+  && dependent_type_p (type)
+  && TYPE_TEMPLATE_INFO (type)
+  /* We detect the generic implicit instantiation A by inspecting
+TYPE_CANONICAL, which lookup_template_class sets to the primary
+template type A.  */
+  && TYPE_CANONICAL (type) == TREE_TYPE (TYPE_TI_TEMPLATE (type)))
+type = TYPE_CANONICAL (type);
+  return type;
+}




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

2024-05-02 Thread Jason Merrill

On 5/1/24 21:34, Nathaniel Shead wrote:

On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:

On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:


On Wed, 1 May 2024, Nathaniel Shead wrote:


Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk (and
later 14.2)?  I don't think making it a GTY root is necessary but I felt
perhaps better to be safe than sorry.

Potentially another approach would be to use DECL_UID instead like how
entity_map does; would that be preferable?

-- >8 --

I got notified by Linaro CI and by checking testresults that there seems
to be some occasional failures in tpl-friend-4_b.C on some architectures
and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
to reproduce but looking at the backtrace I suspect the issue is that
we're adding to the 'imported_temploid_friend' map a decl that is
ultimately discarded, which then has its address reused by a later decl
causing a failure in the assert in 'set_originating_module'.

This patch attempts to fix the issue in two ways: by ensuring that we
only store the decl if we know it's a new decl (and hence won't be
discarded), and by making the imported_temploid_friends map a GTY root
so that even if the decl does get discarded later the address isn't
reused.

gcc/cp/ChangeLog:

* module.cc (imported_temploid_friends): Mark GTY, and...
(init_modules): ...allocate from GGC.
(trees_in::decl_value): Only write to imported_temploid_friends
for new decls.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/module.cc | 7 ---
  1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 5b8ff5bc483..37d38bb9654 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
 need to be attached to the same module as the temploid.  This maps
 these decls to the temploid they are instantiated them, as there is
 no other easy way to get this information.  */
-static hash_map *imported_temploid_friends;
+static GTY(()) hash_map *imported_temploid_friends;
  
  //

  /* Tree streaming.   The tree streaming is very specific to the tree
@@ -8327,7 +8327,8 @@ trees_in::decl_value ()
if (TREE_CODE (inner) == FUNCTION_DECL
|| TREE_CODE (inner) == TYPE_DECL)
  if (tree owner = tree_node ())
-  imported_temploid_friends->put (decl, owner);
+  if (is_new)
+   imported_temploid_friends->put (decl, owner);


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

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

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


Could we instead move the call to propagate_defining_module down a few 
lines, after the pushdecl?



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


It still means garbage entries in the hash_map, which is undesirable 
even if it doesn't cause the same kind of breakage.


Incidentally, decl_tree_map is preferable to hash_map when 
the key is always a decl.


Jason



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

2024-05-02 Thread Jason Merrill

On 5/2/24 10:40, Patrick Palka wrote:

On Thu, 2 May 2024, Nathaniel Shead wrote:


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

Another alternative would be to stream such !DECL_NAME temporaries with
a merge key of MK_unique rather than attempting to find the matching
(nonexistant) field of the class context.


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

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

@@ -8861,28 +8861,6 @@ trees_out::decl_node (tree decl, walk_kind ref)
return false;
  }
  
!  tree ctx = CP_DECL_CONTEXT (decl);

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

  {

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

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

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


Streaming by value sounds right, but as noted an important difference 
between reference temps and others is DECL_NAME.  Perhaps the code 
Patrick quotes could look at that as well as the context?


Jason



Trait built-in naming convention

2024-05-02 Thread Jason Merrill

On 5/2/24 12:45, Jason Merrill wrote:

On 5/2/24 12:20, Ken Matsui wrote:
On Thu, May 2, 2024 at 8:34 AM Ken Matsui  
wrote:


On Thu, May 2, 2024 at 8:16 AM Patrick Palka  wrote:


On Tue, 30 Apr 2024, Jason Merrill wrote:


On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::rank.


__rank seems too short, maybe __array_rank?

Actually, it occurs to me that perhaps we should have been adding 
__builtin to
all of these rather than just __ and the library trait name.  I 
guess it's too
late to do that for the GCC 14 traits, but we could do it for this 
group?


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


Since I had already replaced the prefix locally with __builtin, I
submitted patches addressing all other Jason's reviews with that.
Please let me know if we want to use __ and __array_rank.


If Clang already has a corresponding built-in (as with __array_rank, 
apparently), let's use the same name; otherwise let's add __builtin to 
the new ones.


Eh, this could probably use more discussion.

The practice of omitting __builtin from type-trait builtins goes back to 
Paolo's r123366 (cb68ec50) for 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26099


There was some discussion of how to name the built-ins back in 
https://gcc.gnu.org/pipermail/gcc-patches/2007-March/thread.html#212171

but __builtin wasn't discussed.

Apparently this naming convention follows the MSVC precedent: 
http://msdn2.microsoft.com/en-us/library/ms177194.aspx


I notice some discussion of this pattern around Clang adding various 
built-ins in https://github.com/llvm/llvm-project/issues/61852 
indicating that this is a policy based on precedent.


But I don't see any actual reason for this pattern other than that it's 
what Paolo happened to do in 2007.


I'm not sure what the right way forward is.  Perhaps we're stuck with 
the questionable choices of the past.


Jason



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

2024-05-02 Thread Jason Merrill

On 5/2/24 12:20, Ken Matsui wrote:

On Thu, May 2, 2024 at 8:34 AM Ken Matsui  wrote:


On Thu, May 2, 2024 at 8:16 AM Patrick Palka  wrote:


On Tue, 30 Apr 2024, Jason Merrill wrote:


On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::rank.


__rank seems too short, maybe __array_rank?

Actually, it occurs to me that perhaps we should have been adding __builtin to
all of these rather than just __ and the library trait name.  I guess it's too
late to do that for the GCC 14 traits, but we could do it for this group?


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


Since I had already replaced the prefix locally with __builtin, I
submitted patches addressing all other Jason's reviews with that.
Please let me know if we want to use __ and __array_rank.


If Clang already has a corresponding built-in (as with __array_rank, 
apparently), let's use the same name; otherwise let's add __builtin to 
the new ones.



Oh, then, would using __array_rank and keeping existing built-in
traits as-is sound like a better choice?

https://github.com/llvm/llvm-project/blob/4aca302f5a82ee65847c88500b39a2530dfeceb4/libcxx/include/__type_traits/rank.h#L23






gcc/cp/ChangeLog:

 * cp-trait.def: Define __rank.
 * constraint.cc (diagnose_trait_expr): Handle CPTK_RANK.
 * semantics.cc (trait_expr_value): Likewise.
 (finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

 * g++.dg/ext/has-builtin-1.C: Test existence of __rank.
 * g++.dg/ext/rank.C: New test.

Signed-off-by: Ken Matsui 
---
   gcc/cp/constraint.cc |  3 +++
   gcc/cp/cp-trait.def  |  1 +
   gcc/cp/semantics.cc  | 23 ---
   gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
   gcc/testsuite/g++.dg/ext/rank.C  | 24 
   5 files changed, 51 insertions(+), 3 deletions(-)
   create mode 100644 gcc/testsuite/g++.dg/ext/rank.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 000df847342..23ea66d9c12 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3870,6 +3870,9 @@ diagnose_trait_expr (tree expr, tree args)
   case CPTK_IS_VOLATILE:
 inform (loc, "  %qT is not a volatile type", t1);
 break;
+case CPTK_RANK:
+  inform (loc, "  %qT cannot yield a rank", t1);
+  break;
   case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
 inform (loc, "  %qT is not a reference that binds to a temporary "
   "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2d1cb7c227c..85056c8140b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -99,6 +99,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE,
"__is_trivially_copyable", 1)
   DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
   DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
   DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
+DEFTRAIT_EXPR (RANK, "__rank", 1)
   DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY,
"__reference_constructs_from_temporary", 2)
   DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY,
"__reference_converts_from_temporary", 2)
   DEFTRAIT_TYPE (REMOVE_ALL_EXTENTS, "__remove_all_extents", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 45dc509855a..7242db75248 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12550,6 +12550,9 @@ trait_expr_value (cp_trait_kind kind, tree type1,
tree type2)
   case CPTK_IS_DEDUCIBLE:
 return type_targs_deducible_from (type1, type2);
   +/* __rank is handled in finish_trait_expr. */
+case CPTK_RANK:


This should have a gcc_unreachable.


+
   #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
   case CPTK_##CODE:
   #include "cp-trait.def"
@@ -12622,7 +12625,10 @@ finish_trait_expr (location_t loc, cp_trait_kind
kind, tree type1, tree type2)
 if (processing_template_decl)
   {
 tree trait_expr = make_node (TRAIT_EXPR);
-  TREE_TYPE (trait_expr) = boolean_type_node;
+  if (kind == CPTK_RANK)
+   TREE_TYPE (trait_expr) = size_type_node;
+  else
+   TREE_TYPE (trait_expr) = boolean_type_node;
 TRAIT_EXPR_TYPE1 (trait_expr) = type1;
 TRAIT_EXPR_TYPE2 (trait_expr) = type2;
 TRAIT_EXPR_KIND (trait_expr) = kind;
@@ -12714,6 +12720,7 @@ finish_trait_expr (location_t loc, cp_trait_kind
kind, tree type1, tree type2)
   case CPTK_IS_UNBOUNDED_ARRAY:
   case CPTK_IS_UNION:
   case CPTK_IS_VOLATILE:
+case CPTK_RANK:
 break;
 case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12745,8 +12752,18 @@ finish_trait_expr (location_t loc, cp_trait_kind
kind, tree type1, tree type2)
 gcc_unreachable ();
   }
   -  tree val = (trait_expr_value (k

[PATCH RFA (cgraph)] c++: pragma target and static init [PR109753]

2024-05-02 Thread Jason Merrill
Tested x86_64-pc-linux-gnu, OK for trunk?  14.2?

This two-year-old thread seems relevant:
https://gcc.gnu.org/pipermail/gcc-patches/2022-April/593410.html

-- 8< --

 #pragma target and optimize should also apply to implicitly-generated
 functions like static initialization functions and defaulted special member
 functions.

At least one of the create_same_body_alias/handle_optimize_attribute changes
is necessary to avoid regressing g++.dg/opt/pr105306.C; maybe_clone_body
creates a cgraph_node for the ~B alias before handle_optimize_attribute, and
the alias never goes through finalize_function, so we need to adjust
semantic_interposition somewhere else.

PR c++/109753

gcc/ChangeLog:

* cgraph.cc (cgraph_node::create_same_body_alias): Set
semantic_interposition.

gcc/c-family/ChangeLog:

* c-attribs.cc (handle_optimize_attribute): Set
cgraph_node::semantic_interposition.

gcc/cp/ChangeLog:

* decl.cc (start_preparsed_function): Call decl_attributes.

gcc/testsuite/ChangeLog:

* g++.dg/opt/always_inline1.C: New test.
---
 gcc/c-family/c-attribs.cc | 4 
 gcc/cgraph.cc | 2 ++
 gcc/cp/decl.cc| 3 +++
 gcc/testsuite/g++.dg/opt/always_inline1.C | 8 
 4 files changed, 17 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/opt/always_inline1.C

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 04e39b41bdf..605469dd7dd 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -5971,6 +5971,10 @@ handle_optimize_attribute (tree *node, tree name, tree 
args,
   if (prev_target_node != target_node)
DECL_FUNCTION_SPECIFIC_TARGET (*node) = target_node;
 
+  /* Also update the cgraph_node, if it's already built.  */
+  if (cgraph_node *cn = cgraph_node::get (*node))
+   cn->semantic_interposition = flag_semantic_interposition;
+
   /* Restore current options.  */
   cl_optimization_restore (_options, _options_set,
   _opts);
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 473d8410bc9..f3bd2fa8ece 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -604,6 +604,8 @@ cgraph_node::create_same_body_alias (tree alias, tree decl)
 
   n = cgraph_node::create_alias (alias, decl);
   n->cpp_implicit_alias = true;
+  /* Aliases don't go through finalize_function.  */
+  n->semantic_interposition = opt_for_fn (decl, flag_semantic_interposition);
   if (symtab->cpp_implicit_aliases_done)
 n->resolve_alias (cgraph_node::get (decl));
   return n;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 378311c0f04..4531d830462 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -17796,6 +17796,9 @@ start_preparsed_function (tree decl1, tree attrs, int 
flags)
doing_friend = true;
 }
 
+  /* Adjust for #pragma target/optimize.  */
+  decl_attributes (, NULL_TREE, 0);
+
   if (DECL_DECLARED_INLINE_P (decl1)
   && lookup_attribute ("noinline", attrs))
 warning_at (DECL_SOURCE_LOCATION (decl1), 0,
diff --git a/gcc/testsuite/g++.dg/opt/always_inline1.C 
b/gcc/testsuite/g++.dg/opt/always_inline1.C
new file mode 100644
index 000..a042a1cf0c6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/always_inline1.C
@@ -0,0 +1,8 @@
+// PR c++/109753
+// { dg-do compile { target x86_64-*-* } }
+
+#pragma GCC target("avx2")
+struct aa {
+__attribute__((__always_inline__)) aa() {}
+};
+aa _M_impl;

base-commit: 2f15787f2e1a3afe2c2ad93d4eb0d3c1f73c8fbd
-- 
2.44.0



Re: [PATCH] c++: Clear is_unbraced_* when parsing declaration_seq_opt [PR114917]

2024-05-02 Thread Jason Merrill

On 5/2/24 01:19, Nathaniel Shead wrote:

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


OK.


-- >8 --

Currently we incorrectly retain "in_unbraced_linkage_specification_p"
and "in_unbraced_export_declaration_p" when parsing a (braced)
declaration-seq.  This patch ensures that we clear these flags before
parsing the toplevel declarations.

Strictly speaking we don't need to save and restore the flags around the
parsing because there's currently no way to provide new declarations
within the unbraced context after the closing brace, but this patch does
it anyway in case this ever changes and for consistency with other
places where these flags are adjusted.

PR c++/114917

gcc/cp/ChangeLog:

* parser.cc (cp_parser_declaration_seq_opt): Clear
parser->in_unbraced_* flags when parsing toplevel declarations.

gcc/testsuite/ChangeLog:

* g++.dg/modules/export-5_a.C: New test.
* g++.dg/modules/export-5_b.C: New test.
* g++.dg/parse/linkage4.C: New test.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/parser.cc  | 15 +++
  gcc/testsuite/g++.dg/modules/export-5_a.C | 17 +
  gcc/testsuite/g++.dg/modules/export-5_b.C | 13 +
  gcc/testsuite/g++.dg/parse/linkage4.C | 11 +++
  4 files changed, 56 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/modules/export-5_a.C
  create mode 100644 gcc/testsuite/g++.dg/modules/export-5_b.C
  create mode 100644 gcc/testsuite/g++.dg/parse/linkage4.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index a2bc6f69000..9a39ed27b23 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -15341,6 +15341,16 @@ cp_parser_module_export (cp_parser *parser)
  static void
  cp_parser_declaration_seq_opt (cp_parser* parser)
  {
+  bool saved_in_unbraced_linkage_specification_p
+= parser->in_unbraced_linkage_specification_p;
+  bool saved_in_unbraced_export_declaration_p
+= parser->in_unbraced_export_declaration_p;
+
+  /* We're not in an unbraced linkage-specification
+ or export-declaration anymore.  */
+  parser->in_unbraced_linkage_specification_p = false;
+  parser->in_unbraced_export_declaration_p = false;
+
while (true)
  {
cp_token *token = cp_lexer_peek_token (parser->lexer);
@@ -15351,6 +15361,11 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
else
cp_parser_toplevel_declaration (parser);
  }
+
+  parser->in_unbraced_linkage_specification_p
+= saved_in_unbraced_linkage_specification_p;
+  parser->in_unbraced_export_declaration_p
+= saved_in_unbraced_export_declaration_p;
  }
  
  /* Parse a declaration.  The distinction between name-declaration

diff --git a/gcc/testsuite/g++.dg/modules/export-5_a.C 
b/gcc/testsuite/g++.dg/modules/export-5_a.C
new file mode 100644
index 000..a325591ca8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/export-5_a.C
@@ -0,0 +1,17 @@
+// PR c++/114917
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+
+export namespace ns {
+  template  struct S {};
+  template  struct S { using a = int; };
+  template <> struct S { using b = int; };
+  template struct S;
+};
+
+export extern "C++" namespace ns {
+  template  void foo() {}
+  template <> void foo() {}
+}
diff --git a/gcc/testsuite/g++.dg/modules/export-5_b.C 
b/gcc/testsuite/g++.dg/modules/export-5_b.C
new file mode 100644
index 000..cb10e37c7fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/export-5_b.C
@@ -0,0 +1,13 @@
+// PR c++/114917
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+int main() {
+  ns::S::a x{};
+  ns::S::b y{};
+  ns::S z{};
+
+  ns::foo();
+  ns::foo();
+}
diff --git a/gcc/testsuite/g++.dg/parse/linkage4.C 
b/gcc/testsuite/g++.dg/parse/linkage4.C
new file mode 100644
index 000..10fcc77e9d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/linkage4.C
@@ -0,0 +1,11 @@
+// PR c++/114917
+// { dg-do compile }
+
+extern "C++" namespace ns {
+  struct Incomplete;
+  Incomplete foo;  // { dg-error "incomplete type" }
+}
+
+extern "C" extern "C" {
+  static int bar;  // { dg-bogus "invalid" }
+}




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

2024-05-01 Thread Jason Merrill

On 5/1/24 13:40, Patrick Palka wrote:

On Wed, 1 May 2024, Jason Merrill wrote:


On 5/1/24 12:41, Patrick Palka wrote:

On Fri, 2 Feb 2024, Patrick Palka wrote:


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


Ping, now that stage 1 is open.


Thanks for the ping.  The earlier message isn't showing up in Thunderbird for
some reason, though I see it in the gmail web interface...


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




@@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
ctx = TREE_VEC_ELT (ctx, 0);
  }
else
- ctx = tsubst_aggr_type (ctx, args,
- complain | tf_qualifying_scope,
- in_decl, /*entering_scope=*/1);
+ {
+   ctx = tsubst_scope (ctx, args, complain, in_decl);


Why is this one tsubst_scope while the others are all plain tsubst?


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


Do we want a tsubst_entering_scope function?


Which is just shorthand for tsubst + adjust_type_for_entering_scope?


That's what I was thinking.


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


I don't think we want that; having the distinction helps to avoid 
wrongly looking up members of the primary template in contexts that 
shouldn't be able to.


Jason



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

2024-05-01 Thread Jason Merrill

On 4/12/24 13:22, Patrick Palka wrote:

On Fri, 12 Apr 2024, Jason Merrill wrote:


On 3/26/24 09:44, Patrick Palka wrote:

On Thu, 7 Mar 2024, Jason Merrill wrote:


On 1/29/24 17:42, Patrick Palka wrote:

On Mon, 29 Jan 2024, Patrick Palka wrote:


On Fri, 26 Jan 2024, Jason Merrill wrote:


On 1/26/24 17:11, Jason Merrill wrote:

On 1/26/24 16:52, Jason Merrill wrote:

On 1/25/24 14:18, Patrick Palka wrote:

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this
look
OK for trunk/13?  This isn't a very satisfactory fix, but at
least
it safely fixes these testcases I guess.  Note that there's
implementation disagreement about the second testcase, GCC
always
accepted it but Clang/MSVC/icc reject it.


Because of trying to initialize int& from {c}; removing the
extra
braces
makes it work everywhore.

https://eel.is/c++draft/dcl.init#list-3.10 says that we always
generate a
prvalue in this case, so perhaps we shouldn't recalculate if the
initializer is an init-list?


...but it seems bad to silently bind a const int& to a prvalue
instead
of
directly to the reference returned by the operator, as clang does
if
we add
const to the second testcase, so I think there's a defect in the
standard
here.


Perhaps bullet 3.9 should change to "...its referenced type is
reference-related to E or scalar, ..."


Maybe for now also disable the maybe_valid heuristics in the case
of
an
init-list?


The first testcase is special because it's a C-style cast; seems
like the
maybe_valid = false heuristics should be disabled if c_cast_p.


Thanks a lot for the pointers.  IIUC c_cast_p and
LOOKUP_SHORTCUT_BAD_CONVS
should already be mutually exclusive, since the latter is set only
when
computing argument conversions, so it shouldn't be necessary to check
c_cast_p.

I suppose we could disable the heuristic for init-lists, but after
some
digging I noticed that the heuristics were originally in same spot
they
are now until r5-601-gd02f620dc0bb3b moved them to get checked after
the recursive recalculation case in reference_binding, returning a bad
conversion instead of NULL.  (Then in r13-1755-g68f37670eff0b872 I
moved
them back; IIRC that's why I felt confident that moving the checks was
safe.)
Thus we didn't always accept the second testcase, we only started
doing so
in
GCC 5: https://godbolt.org/z/6nsEW14fh (sorry for missing this and
saying
we
always accepted it)

And indeed the current order of checks seems consistent with that of
[dcl.init.ref]/5.  So I wonder if we don't instead want to "complete"
the NULL-to-bad-conversion adjustment in r5-601-gd02f620dc0bb3b and
do:

gcc/cp/ChangeLog:

* call.cc (reference_binding): Set bad_p according to
maybe_valid_p in the recursive case as well.  Remove
redundant gcc_assert.

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 9de0d77c423..c4158b2af37 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2033,8 +2033,8 @@ reference_binding (tree rto, tree rfrom, tree
expr,
bool c_cast_p, int flags,
   sflags, complain);
if (!new_second)
  return bad_direct_conv ? bad_direct_conv : nullptr;
+   t->bad_p = !maybe_valid_p;


Oops, that should be |= not =.


Perhaps bullet 3.9 should change to "...its referenced type is
reference-related to E or scalar, ..."

conv = merge_conversion_sequences (t, new_second);
-   gcc_assert (maybe_valid_p || conv->bad_p);
return conv;
  }
}

This'd mean we'd go back to rejecting the second testcase (only the
call, not the direct-init, interestingly enough), but that seems to be


In the second testcase, with the above fix initialize_reference silently
returns error_mark_node for the direct-init without issuing a
diagnostic, because in the error path convert_like doesn't find anything
wrong with the bad conversion.  So more changes need to be made if we
want to set bad_p in the recursive case of reference_binding it seems;
dunno if that's the path we want to go down?

On the other hand, disabling the badness checks in certain cases seems
to be undesirable as well, since AFAICT their current position is
consistent with [dcl.init.ref]/5?

So I wonder if we should just go with the safest thing at this stage,
which would be the original patch that removes the problematic assert?


I still think the assert is correct, and the problem is that maybe_valid_p
is
wrong; these cases turn out to be valid, so maybe_valid_p should be true.


I'm afraid then I don't know how we can statically identify these cases
without actually performing the conversion, in light of the recursion :/
Do you mind taking this PR?  I don't feel well-versed enough with the
reference binding rules to tackle this adequately..


That ended up being a surprisingly deep dive, but I've now checked in separate
fixes for the two cases.


Very interesting, thanks a lot.


...but I don't think my fixes are suitable f

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

2024-05-01 Thread Jason Merrill

On 5/1/24 12:11, Patrick Palka wrote:

On Wed, 1 May 2024, Jason Merrill wrote:


On 5/1/24 08:54, Patrick Palka wrote:

On Thu, 2 May 2024, Nathaniel Shead wrote:


On Wed, May 01, 2024 at 10:11:20AM -0400, Patrick Palka wrote:

On Wed, 1 May 2024, Nathaniel Shead wrote:


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

-- >8 --

When calling instantiate_pending_templates at end of parsing, any new
functions that are instantiated from this point have their module
purview set based on the current value of module_kind.

This is unideal, however, as the modules code will then treat these
instantiations as reachable and cause large swathes of the GMF to be
emitted into the module CMI, despite no code in the actual module
purview referencing it.

This patch fixes this by also remembering the value of module_kind
when
the instantiation was deferred, and restoring it when doing this
deferred instantiation.  That way newly instantiated declarations
appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
instantiation was required, meaning that GMF entities won't be counted
as reachable unless referenced by an actually reachable entity.

Note that purviewness and attachment etc. is generally only determined
by the base template: this is purely for determining whether a
specialisation was declared in the module purview and hence whether it
should be streamed out.  See the comment on
'set_instantiating_module'.

PR c++/114630
PR c++/114795

gcc/cp/ChangeLog:

* cp-tree.h (struct tinst_level): Add field for tracking
module_kind.
* pt.cc (push_tinst_level_loc): Cache module_kind in
new_level.
(reopen_tinst_level): Restore module_kind from level.
(instantiate_pending_templates): Save and restore module_kind
so
it isn't affected by reopen_tinst_level.


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

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

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



Hm..., so I believe it'll be marked according to whichever instantiates
it "first", so if e.g. deferred from GMF and then instantiated
non-deferred from purview it'll be marked purview (and the deferred
instantiation will be skipped as it's already instantiated).  This could
mean it gets unnecessarily emitted if it only got instantiated because
it got used in e.g. a non-inline function body, I suppose; but that's
true in general actually, at the moment.


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

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

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

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


Does the explicit instantiation change that at all?  Either way it seams like
f and f aren't decl-reachable from w if we determine that after constant
evaluation.


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

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

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

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


Agreed, because f is decl-reachable from the explicit instantiation in 
the module purview.


I was suggesting that there's no effective difference between explicit 
instantiation in the GMF and implicit instantiation.


Jason



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

2024-05-01 Thread Jason Merrill

On 5/1/24 12:41, Patrick Palka wrote:

On Fri, 2 Feb 2024, Patrick Palka wrote:


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


Ping, now that stage 1 is open.


Thanks for the ping.  The earlier message isn't showing up in 
Thunderbird for some reason, though I see it in the gmail web interface...



@@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
ctx = TREE_VEC_ELT (ctx, 0);
  }
else
- ctx = tsubst_aggr_type (ctx, args,
- complain | tf_qualifying_scope,
- in_decl, /*entering_scope=*/1);
+ {
+   ctx = tsubst_scope (ctx, args, complain, in_decl);


Why is this one tsubst_scope while the others are all plain tsubst?

Do we want a tsubst_entering_scope function?


+   ctx = adjust_type_for_entering_scope (ctx);




[pushed] c++: drop in-charge for dtors without vbases

2024-05-01 Thread Jason Merrill
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

Constructors and destructors use the in-charge parameter to decide whether
they're responsible for recursing into virtual bases.  Historically all
destructors had this parameter in order to also distinguish the deleting
destructor.  But r151673 in GCC 4.5 changed the deleting destructor to just
call the complete destructor and then operator delete, making the in-charge
parameter no longer relevant for destructors in classes without virtual
bases.  Having it causes confusion in constexpr evaluation, which assumes
that clones will have the same parameters as the cloned 'tor.

gcc/cp/ChangeLog:

* cp-tree.h (base_ctor_identifier): Adjust comment.
* call.cc (in_charge_arg_for_name): Abort on deleting dtor.
* decl2.cc (maybe_retrofit_in_chrg): Don't add it for
destructors without vbases, either.
* constexpr.cc (cxx_eval_call_expression): Remove workaround.

gcc/testsuite/ChangeLog:

* g++.dg/debug/dwarf2/array-3.C: No more 'int' for in-chrg parm.
* g++.dg/debug/dwarf2/array-4.C: Likewise.
---
 gcc/cp/cp-tree.h|  3 +--
 gcc/cp/call.cc  |  4 +++-
 gcc/cp/constexpr.cc | 20 +++-
 gcc/cp/decl2.cc | 12 
 gcc/testsuite/g++.dg/debug/dwarf2/array-3.C |  6 +++---
 gcc/testsuite/g++.dg/debug/dwarf2/array-4.C |  2 +-
 6 files changed, 19 insertions(+), 28 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1938ada0268..5d1bd6ba493 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -289,8 +289,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 /* The name of a constructor that does not construct virtual base classes.  */
 #define base_ctor_identifier   
cp_global_trees[CPTI_BASE_CTOR_IDENTIFIER]
 /* The name of a destructor that takes an in-charge parameter to
-   decide whether or not to destroy virtual base classes and whether
-   or not to delete the object.  */
+   decide whether or not to destroy virtual base classes.  */
 #define dtor_identifier
cp_global_trees[CPTI_DTOR_IDENTIFIER]
 /* The name of a destructor that destroys virtual base classes.  */
 #define complete_dtor_identifier   
cp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER]
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index dbdd7c29fe8..7c4ecf08c4b 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -11167,7 +11167,9 @@ in_charge_arg_for_name (tree name)
   if (name == complete_dtor_identifier)
return integer_two_node;
   else if (name == deleting_dtor_identifier)
-   return integer_three_node;
+   /* The deleting dtor should now be handled by
+  build_delete_destructor_body.  */
+   gcc_unreachable ();
   gcc_checking_assert (name == base_dtor_identifier);
 }
 
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8078b31544d..50f799d7ff7 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3243,19 +3243,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
tree t,
  ctx->global->put_value (remapped, arg);
  remapped = DECL_CHAIN (remapped);
}
- for (; remapped; remapped = TREE_CHAIN (remapped))
-   if (DECL_NAME (remapped) == in_charge_identifier)
- {
-   /* FIXME destructors unnecessarily have in-charge parameters
-  even in classes without vbases, map it to 0 for now.  */
-   gcc_assert (!CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)));
-   ctx->global->put_value (remapped, integer_zero_node);
- }
-   else
- {
-   gcc_assert (seen_error ());
-   *non_constant_p = true;
- }
+ if (remapped)
+   {
+ /* We shouldn't have any parms without args, but fail gracefully
+in error recovery.  */
+ gcc_checking_assert (seen_error ());
+ *non_constant_p = true;
+   }
  /* Add the RESULT_DECL to the values map, too.  */
  gcc_assert (!DECL_BY_REFERENCE (res));
  ctx->global->put_value (res, NULL_TREE);
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 806a2a4bc69..b8dc55b51d9 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -275,11 +275,8 @@ build_artificial_parm (tree fn, tree name, tree type)
   return parm;
 }
 
-/* Constructors for types with virtual baseclasses need an "in-charge" flag
-   saying whether this constructor is responsible for initialization of
-   virtual baseclasses or not.  All destructors also need this "in-charge"
-   flag, which additionally determines whether or not the destructor should
-   free the memory for the object.
+/* 'structors for types with virtual baseclasses need an "in-charge" flag
+   saying whether this function is responsible for virtual baseclasses or not.
 
This 

Re: [PATCH] c++: Implement C++26 P2573R2 - = delete("should have a reason"); [PR114458]

2024-05-01 Thread Jason Merrill

On 5/1/24 23:33, Jakub Jelinek wrote:


The following patch implements the C++26 P2573R2
= delete("should have a reason"); paper.
I've tried to avoid increasing compile time memory for it when it isn't
used (e.g. by adding a new lang_decl tree member), so the reason is
represented as STRING_CST in DECL_INITIAL (which normally is for
DECL_DELETED_FN error_mark_node) and to differentiate this delete("reason")
initializer from some bogus attempt to initialize a function with "reason"
using the RID_DELETE identifier as TREE_TYPE of the STRING_CST, as nothing
needs to care about the type of the reason.  If preferred it could
be say TREE_LIST with the reason STRING_CST and RID_DELETE identifier or
something similar instead, but that would need more compile time memory when
it is used.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


Please add a comment about this representation to the definition of 
DECL_DELETED_FN.  OK with that change.



2024-05-01  Jakub Jelinek  

PR c++/114458
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine
__cpp_deleted_function=202403L for C++26.
gcc/cp/ChangeLog
* parser.cc (cp_parser_pure_specifier): Implement C++26 P2573R2
- = delete("should have a reason");.  Parse deleted-function-body.
* decl.cc (duplicate_decls): Copy DECL_INITIAL from DECL_DELETED_FN
olddecl to newdecl if it is a STRING_CST.
(cp_finish_decl): Handle deleted init with a reason.
* decl2.cc: Include "escaped_string.h".
(grokfield): Handle deleted init with a reason.
(mark_used): Emit DECL_DELETED_FN reason in the message if any.
gcc/testsuite/
* g++.dg/cpp26/feat-cxx26.C (__cpp_deleted_function): Add test.
* g++.dg/cpp26/delete-reason1.C: New test.
* g++.dg/cpp26/delete-reason2.C: New test.
* g++.dg/parse/error65.C (f1): Adjust expected diagnostics.

--- gcc/c-family/c-cppbuiltin.cc.jj 2024-04-30 08:57:07.359039013 +0200
+++ gcc/c-family/c-cppbuiltin.cc2024-04-30 19:16:45.069542205 +0200
@@ -1092,6 +1092,7 @@ c_cpp_builtins (cpp_reader *pfile)
  cpp_define (pfile, "__cpp_static_assert=202306L");
  cpp_define (pfile, "__cpp_placeholder_variables=202306L");
  cpp_define (pfile, "__cpp_structured_bindings=202403L");
+ cpp_define (pfile, "__cpp_deleted_function=202403L");
}
if (flag_concepts)
  {
--- gcc/cp/parser.cc.jj 2024-04-30 08:57:07.349039147 +0200
+++ gcc/cp/parser.cc2024-04-30 16:47:01.427952875 +0200
@@ -28573,6 +28573,27 @@ cp_parser_pure_specifier (cp_parser* par
|| token->keyword == RID_DELETE)
  {
maybe_warn_cpp0x (CPP0X_DEFAULTED_DELETED);
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+   {
+ if (cxx_dialect >= cxx11 && cxx_dialect < cxx26)
+   pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+OPT_Wc__26_extensions,
+"% reason only available with "
+"%<-std=c++2c%> or %<-std=gnu++2c%>");
+
+ /* Consume the `('.  */
+ matching_parens parens;
+ parens.consume_open (parser);
+ tree reason = cp_parser_unevaluated_string_literal (parser);
+ /* Consume the `)'.  */
+ parens.require_close (parser);
+ if (TREE_CODE (reason) == STRING_CST)
+   {
+ TREE_TYPE (reason) = token->u.value;
+ return reason;
+   }
+   }
+
return token->u.value;
  }
  
--- gcc/cp/decl.cc.jj	2024-04-30 08:55:26.172389593 +0200

+++ gcc/cp/decl.cc  2024-04-30 19:01:32.316543498 +0200
@@ -2410,6 +2410,10 @@ duplicate_decls (tree newdecl, tree oldd
"previous declaration of %qD", olddecl);
}
  DECL_DELETED_FN (newdecl) |= DECL_DELETED_FN (olddecl);
+ if (DECL_DELETED_FN (olddecl)
+ && DECL_INITIAL (olddecl)
+ && TREE_CODE (DECL_INITIAL (olddecl)) == STRING_CST)
+   DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
}
  }
  
@@ -8587,17 +8591,20 @@ cp_finish_decl (tree decl, tree init, bo

if (init && TREE_CODE (decl) == FUNCTION_DECL)
  {
tree clone;
-  if (init == ridpointers[(int)RID_DELETE])
+  if (init == ridpointers[(int)RID_DELETE]
+ || (TREE_CODE (init) == STRING_CST
+ && 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) = error_mark_node;
+ 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) = error_mark_node;
+ DECL_INITIAL (clone) 

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

2024-05-01 Thread Jason Merrill

On 5/1/24 08:54, Patrick Palka wrote:

On Thu, 2 May 2024, Nathaniel Shead wrote:


On Wed, May 01, 2024 at 10:11:20AM -0400, Patrick Palka wrote:

On Wed, 1 May 2024, Nathaniel Shead wrote:


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

-- >8 --

When calling instantiate_pending_templates at end of parsing, any new
functions that are instantiated from this point have their module
purview set based on the current value of module_kind.

This is unideal, however, as the modules code will then treat these
instantiations as reachable and cause large swathes of the GMF to be
emitted into the module CMI, despite no code in the actual module
purview referencing it.

This patch fixes this by also remembering the value of module_kind when
the instantiation was deferred, and restoring it when doing this
deferred instantiation.  That way newly instantiated declarations
appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
instantiation was required, meaning that GMF entities won't be counted
as reachable unless referenced by an actually reachable entity.

Note that purviewness and attachment etc. is generally only determined
by the base template: this is purely for determining whether a
specialisation was declared in the module purview and hence whether it
should be streamed out.  See the comment on 'set_instantiating_module'.

PR c++/114630
PR c++/114795

gcc/cp/ChangeLog:

* cp-tree.h (struct tinst_level): Add field for tracking
module_kind.
* pt.cc (push_tinst_level_loc): Cache module_kind in new_level.
(reopen_tinst_level): Restore module_kind from level.
(instantiate_pending_templates): Save and restore module_kind so
it isn't affected by reopen_tinst_level.


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

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

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



Hm..., so I believe it'll be marked according to whichever instantiates
it "first", so if e.g. deferred from GMF and then instantiated
non-deferred from purview it'll be marked purview (and the deferred
instantiation will be skipped as it's already instantiated).  This could
mean it gets unnecessarily emitted if it only got instantiated because
it got used in e.g. a non-inline function body, I suppose; but that's
true in general actually, at the moment.


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

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

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

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


Does the explicit instantiation change that at all?  Either way it seams 
like f and f aren't decl-reachable from w if we determine that 
after constant evaluation.


Jason



[pushed] c++: const void* memchr [PR113706]

2024-05-01 Thread Jason Merrill
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

The C++ standard specifies that the  functions have const and
non-const overloads, unlike C's single function with const argument and
non-const return.  Many systems don't actually implement this, but only add
an overload with non-const argument, so both end up having non-const return.
Solaris  does what the standard says, but we were penalizing it by
not recognizing the const overload as the built-in memchr.

PR c++/113706

gcc/cp/ChangeLog:

* decl.cc (decls_match): Handle memchr return type being
const-qualified.

gcc/testsuite/ChangeLog:

* g++.dg/opt/const-builtin1.C: New test.
* c-c++-common/pr103798-2.c: Remove xfail.
---
 gcc/cp/decl.cc| 10 +++
 gcc/testsuite/c-c++-common/pr103798-2.c   |  3 +--
 gcc/testsuite/g++.dg/opt/const-builtin1.C | 33 +++
 3 files changed, 44 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/const-builtin1.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d88e0698652..df855334133 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1156,6 +1156,16 @@ decls_match (tree newdecl, tree olddecl, bool 
record_versions /* = true */)
   tree r2 = fndecl_declared_return_type (olddecl);
   tree r1 = fndecl_declared_return_type (newdecl);
 
+  /* For memchr et al, allow const void* return type (as specified by C++)
+when we expect void* (as in C).  */
+  if (DECL_IS_UNDECLARED_BUILTIN (olddecl)
+ && DECL_EXTERN_C_P (olddecl)
+ && !same_type_p (r1, r2)
+ && TREE_CODE (r1) == POINTER_TYPE
+ && TREE_CODE (r2) == POINTER_TYPE
+ && comp_ptr_ttypes (TREE_TYPE (r1), TREE_TYPE (r2)))
+   r2 = r1;
+
   tree p1 = TYPE_ARG_TYPES (f1);
   tree p2 = TYPE_ARG_TYPES (f2);
 
diff --git a/gcc/testsuite/c-c++-common/pr103798-2.c 
b/gcc/testsuite/c-c++-common/pr103798-2.c
index 83cdfaa1660..e7e99c3679e 100644
--- a/gcc/testsuite/c-c++-common/pr103798-2.c
+++ b/gcc/testsuite/c-c++-common/pr103798-2.c
@@ -27,5 +27,4 @@ main ()
  return 0;
 }
 
-/* See PR c++/113706 for the xfail.  */
-/* { dg-final { scan-assembler-not "memchr" { xfail { c++ && { *-*-solaris2* 
*-*-vxworks* } } } } } */
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/g++.dg/opt/const-builtin1.C 
b/gcc/testsuite/g++.dg/opt/const-builtin1.C
new file mode 100644
index 000..8b9987271c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/const-builtin1.C
@@ -0,0 +1,33 @@
+// PR c++/113706
+/* A variant of the pr103798-2.c test with const void * memchr return type, as
+   specified by the C++ standard.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+extern "C" const void *memchr (const void *, int, __SIZE_TYPE__); // { 
dg-bogus "built-in" }
+
+__attribute__ ((weak))
+int
+f (int a)
+{
+   return memchr ("aE", a, 2) != 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+  return a == 'a' || a == 'E';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+   if (f (i + 256) != g (i + 256))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */

base-commit: c60b3e211c555706cdc2dc8bfcdd540152cff350
-- 
2.44.0



Re: [PATCH v4 4/4] Update the C/C++ FE routines

2024-05-01 Thread Jason Merrill

On 5/1/24 08:19, Qing Zhao wrote:

  "add_flexible_array_elts_to_size" and "layout_var_decl"  to handle
  the cases when the DECL is union.

Add testing cases to test the _bos for flexible array members in unions
or alone in structures.

gcc/c/ChangeLog:

* c-decl.cc (add_flexible_array_elts_to_size): Handle the cases
when the DECL is union.

gcc/cp/ChangeLog:

* decl.cc (layout_var_decl): Handle the cases when the DECL is
union with a flexible array member initializer.

gcc/testsuite/ChangeLog:

* c-c++-common/fam-in-union-alone-in-struct-bos-1.c: New test.
* c-c++-common/fam-in-union-alone-in-struct-bos.c: New test.
---
  gcc/c/c-decl.cc   | 30 +++--
  gcc/cp/decl.cc| 32 +++--
  .../fam-in-union-alone-in-struct-bos-1.c  | 66 +++
  .../fam-in-union-alone-in-struct-bos.c| 45 +
  4 files changed, 159 insertions(+), 14 deletions(-)
  create mode 100644 
gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos-1.c
  create mode 100644 
gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 947f3cd589eb..9ba92690daf5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5337,9 +5337,9 @@ zero_length_array_type_p (const_tree type)
  }
  
  /* INIT is a constructor that forms DECL's initializer.  If the final

-   element initializes a flexible array field, add the size of that
-   initializer to DECL's size.  */
-


Please keep the blank line between the comment and the function.  Please 
post the adjusted patch, but no need to wait for approval again, the 
patch series is OK.



+   element initializes a flexible array field, adjust the size of the
+   DECL with the initializer based on whether the DECL is a union or
+   a structure.  */
  static void
  add_flexible_array_elts_to_size (tree decl, tree init)
  {
@@ -5353,10 +5353,26 @@ add_flexible_array_elts_to_size (tree decl, tree init)
if (flexible_array_member_type_p (type))
  {
complete_array_type (, elt, false);
-  DECL_SIZE (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
-  DECL_SIZE_UNIT (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type));
+  /* For a structure, add the size of the initializer to the DECL's
+size.  */
+  if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+   {
+ DECL_SIZE (decl)
+   = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
+ DECL_SIZE_UNIT (decl)
+   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl),
+ TYPE_SIZE_UNIT (type));
+   }
+  /* For a union, the DECL's size is the maximum of the current size
+and the size of the initializer.  */
+  else
+   {
+ DECL_SIZE (decl)
+   = size_binop (MAX_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
+ DECL_SIZE_UNIT (decl)
+   = size_binop (MAX_EXPR, DECL_SIZE_UNIT (decl),
+ TYPE_SIZE_UNIT (type));
+   }
  }
  }
  
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9a91c6f80da1..78e21b05296c 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6555,8 +6555,9 @@ layout_var_decl (tree decl)
}
  }
  
-  /* If the final element initializes a flexible array field, add the size of

- that initializer to DECL's size.  */
+  /* If the final element initializes a flexible array field, adjust
+ the size of the DECL with the initializer based on whether the
+ DECL is a union or a structure.  */
if (type != error_mark_node
&& DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR
@@ -6577,11 +6578,28 @@ layout_var_decl (tree decl)
  && TREE_CODE (vtype) == ARRAY_TYPE
  && COMPLETE_TYPE_P (vtype))
{
- DECL_SIZE (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (vtype));
- DECL_SIZE_UNIT (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl),
- TYPE_SIZE_UNIT (vtype));
+ /* For a structure, add the size of the initializer to the DECL's
+size.  */
+ if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+   {
+ DECL_SIZE (decl)
+   = size_binop (PLUS_EXPR, DECL_SIZE (decl),
+ TYPE_SIZE (vtype));
+ DECL_SIZE_UNIT (decl)
+   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl),
+ TYPE_SIZE_UNIT (vtype));
+   }
+ /* For a union, the DECL's size is the maximum of the current size
+and the size of the initializer.  */
+ else
+   {
+ DECL_SIZE (decl)
+   = size_binop (MAX_EXPR, DECL_SIZE (decl),
+ 

Re: [PATCH 4/4] c++: Add new xtreme-header testcase for GMF discarding

2024-05-01 Thread Jason Merrill

On 5/1/24 03:01, Nathaniel Shead wrote:

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


OK.


Another thought would be to replace xtreme-header.h with  so
that we don't need to keep it up-to-date in the future.  But this patch just
does the obviously correct thing.

-- >8 --

This new testcase helps verify that the issues discovered in PR114630
with GMF entries being inappropriately emitted into the module CMI don't
regress, at least for the kinds of code used in the standard library
headers.

This also updates the base xtreme-header.h file to include new header
files that are now available.

gcc/testsuite/ChangeLog:

* g++.dg/modules/xtreme-header.h: Update.
* g++.dg/modules/xtreme-header-8.C: New test.

Signed-off-by: Nathaniel Shead 
---
  .../g++.dg/modules/xtreme-header-8.C  |  9 +++
  gcc/testsuite/g++.dg/modules/xtreme-header.h  | 24 ---
  2 files changed, 25 insertions(+), 8 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/modules/xtreme-header-8.C

diff --git a/gcc/testsuite/g++.dg/modules/xtreme-header-8.C 
b/gcc/testsuite/g++.dg/modules/xtreme-header-8.C
new file mode 100644
index 000..b0d0ae87534
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/xtreme-header-8.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+// { dg-module-cmi empty }
+
+module;
+#include "xtreme-header.h"
+export module empty;
+
+// The whole GMF should be discarded here
+// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }
diff --git a/gcc/testsuite/g++.dg/modules/xtreme-header.h 
b/gcc/testsuite/g++.dg/modules/xtreme-header.h
index 3147aaf00f4..8d95218755a 100644
--- a/gcc/testsuite/g++.dg/modules/xtreme-header.h
+++ b/gcc/testsuite/g++.dg/modules/xtreme-header.h
@@ -89,7 +89,6 @@
  
  // C++20

  #if __cplusplus > 201703
-#if 1
  #include 
  #include 
  #include 
@@ -98,6 +97,7 @@
  #if __cpp_coroutines
  #include 
  #endif
+#include 
  #include 
  #include 
  #include 
@@ -106,24 +106,32 @@
  #include 
  #include 
  #include 
-#if 0
-// Unimplemented
-#include 
-#endif
-#endif
  #endif
  
  // C++23

  #if __cplusplus > 202002L
  #include 
+#include 
+#include 
  #include 
  #include 
+#include 
  #if 0
  // Unimplemented
  #include 
  #include 
-#include 
  #include 
-#include 
+#endif
+#endif
+
+// C++26
+#if __cplusplus > 202302L
+#if 0
+// Unimplemented
+#include 
+#include 
+#include 
+#include 
+#include 
  #endif
  #endif




Re: [PATCH 1/4] c++/modules: Don't emit unused GMF partial specializations [PR114630]

2024-05-01 Thread Jason Merrill

On 5/1/24 02:59, Nathaniel Shead wrote:

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


OK.


-- >8 --

The change in r14-8408 to also emit partial specializations in the
global module fragment caused the regression in the linked PR; this
patch fixes this by restricting emitted GM partial specializations to
those that are actually used.

PR c++/114630

gcc/cp/ChangeLog:

* module.cc (depset::hash::add_partial_entities): Mark GM
specializations as unreached.
(depset::hash::find_dependencies): Also reach entities in the
DECL_TEMPLATE_SPECIALIZATIONS list.

gcc/testsuite/ChangeLog:

* g++.dg/modules/partial-3.C: New test.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/module.cc | 75 +++-
  gcc/testsuite/g++.dg/modules/partial-3.C | 20 +++
  2 files changed, 66 insertions(+), 29 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/modules/partial-3.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index fac0301d80e..02b0ab3d687 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13304,14 +13304,22 @@ depset::hash::add_partial_entities (vec 
*partial_classes)
depset *dep = make_dependency (inner, depset::EK_DECL);
  
if (dep->get_entity_kind () == depset::EK_REDIRECT)

-   /* We should have recorded the template as a partial
-  specialization.  */
-   gcc_checking_assert (dep->deps[0]->get_entity_kind ()
-== depset::EK_PARTIAL);
+   {
+ dep = dep->deps[0];
+ /* We should have recorded the template as a partial
+specialization.  */
+ gcc_checking_assert (dep->get_entity_kind ()
+  == depset::EK_PARTIAL);
+   }
else
/* It was an explicit specialization, not a partial one.  */
gcc_checking_assert (dep->get_entity_kind ()
 == depset::EK_SPECIALIZATION);
+
+  /* Only emit GM entities if reached.  */
+  if (!DECL_LANG_SPECIFIC (inner)
+ || !DECL_MODULE_PURVIEW_P (inner))
+   dep->set_flag_bit ();
  }
  }
  
@@ -13632,31 +13640,40 @@ depset::hash::find_dependencies (module_state *module)

  if (!walker.is_key_order ()
  && TREE_CODE (decl) == TEMPLATE_DECL
  && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
-   /* Mark all the explicit & partial specializations as
-  reachable.  */
-   for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl);
-cons; cons = TREE_CHAIN (cons))
- {
-   tree spec = TREE_VALUE (cons);
-   if (TYPE_P (spec))
- spec = TYPE_NAME (spec);
-   int use_tpl;
-   node_template_info (spec, use_tpl);
-   if (use_tpl & 2)
- {
-   depset *spec_dep = find_dependency (spec);
-   if (spec_dep->get_entity_kind () == EK_REDIRECT)
- spec_dep = spec_dep->deps[0];
-   if (spec_dep->is_unreached ())
- {
-   reached_unreached = true;
-   spec_dep->clear_flag_bit ();
-   dump (dumper::DEPEND)
- && dump ("Reaching unreached specialization"
-  " %C:%N", TREE_CODE (spec), spec);
- }
- }
- }
+   {
+ /* Mark all the explicit & partial specializations as
+reachable.  We search both specialization lists as some
+constrained partial specializations for class types are
+only found in DECL_TEMPLATE_SPECIALIZATIONS.  */
+ auto mark_reached = [this](tree spec)
+   {
+ if (TYPE_P (spec))
+   spec = TYPE_NAME (spec);
+ int use_tpl;
+ node_template_info (spec, use_tpl);
+ if (use_tpl & 2)
+   {
+ depset *spec_dep = find_dependency (spec);
+ if (spec_dep->get_entity_kind () == EK_REDIRECT)
+   spec_dep = spec_dep->deps[0];
+ if (spec_dep->is_unreached ())
+   {
+ reached_unreached = true;
+ spec_dep->clear_flag_bit ();
+ dump (dumper::DEPEND)
+   && dump ("Reaching unreached specialization"
+" %C:%N", TREE_CODE (spec), spec);
+   }
+   }
+   };
+
+ for (tree cons = DECL_TEMPLATE_INSTANTIATIONS 

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

2024-05-01 Thread Jason Merrill

On 5/1/24 07:11, Patrick Palka wrote:

On Wed, 1 May 2024, Nathaniel Shead wrote:


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

-- >8 --

When calling instantiate_pending_templates at end of parsing, any new
functions that are instantiated from this point have their module
purview set based on the current value of module_kind.

This is unideal, however, as the modules code will then treat these
instantiations as reachable and cause large swathes of the GMF to be
emitted into the module CMI, despite no code in the actual module
purview referencing it.

This patch fixes this by also remembering the value of module_kind when
the instantiation was deferred, and restoring it when doing this
deferred instantiation.  That way newly instantiated declarations
appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
instantiation was required, meaning that GMF entities won't be counted
as reachable unless referenced by an actually reachable entity.

Note that purviewness and attachment etc. is generally only determined
by the base template: this is purely for determining whether a
specialisation was declared in the module purview and hence whether it
should be streamed out.  See the comment on 'set_instantiating_module'.

PR c++/114630
PR c++/114795

gcc/cp/ChangeLog:

* cp-tree.h (struct tinst_level): Add field for tracking
module_kind.
* pt.cc (push_tinst_level_loc): Cache module_kind in new_level.
(reopen_tinst_level): Restore module_kind from level.
(instantiate_pending_templates): Save and restore module_kind so
it isn't affected by reopen_tinst_level.


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


Hmm, I actually think I like the approach of instantiating at that point 
better, so that instantiations in the GMF can't depend on things in 
module purview.


And probably do the same again when switching to the private module 
fragment, when that's implemented.


Jason



Re: [PATCH] c++: Implement modules ABI for vtable emissions

2024-05-01 Thread Jason Merrill

On 5/1/24 04:37, Nathaniel Shead wrote:

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

-- >8 --

This patch implements the changes described in
https://github.com/itanium-cxx-abi/cxx-abi/pull/171.

One restriction that is lifted in the ABI that hasn't been updated here
is that the ABI no longer requires unique vtables to be emitted with
vague linkage.  I haven't changed this behaviour for this patch, but in
the future we should probably look into changing the relevant target
hook ('class_data_always_comdat') to default to 'false'.


I suppose we could, but it seems unnecessary.  We've previously decided 
to use COMDAT even when we know that a vague linkage entity is only 
emitted in one TU.  For instance, sticking with COMDAT is more forgiving 
to changes in key function identification.


The patch is OK.

Jason



Re: [PATCH v3 1/4] Allow flexible array members in unions and alone in structures [PR53548]

2024-04-30 Thread Jason Merrill

On 4/30/24 14:49, Qing Zhao wrote:




On Apr 30, 2024, at 15:45, Qing Zhao  wrote:




 gcc/doc/extend.texi | 34 ++
 1 file changed, 34 insertions(+)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7b54a241a7bf..cba98c8aadd7 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -42,6 +42,8 @@ extensions, accepted by GCC in C90 mode and in C++.
 * Named Address Spaces::Named address spaces.
 * Zero Length:: Zero-length arrays.
 * Empty Structures::    Structures with no members.
+* Flexible Array Members in Unions::  Unions with Flexible Array 
Members.
+* Flexible Array Members alone in Structures::  Structures with 
only Flexible Array Members.

 * Variable Length:: Arrays whose length is computed at run time.
 * Variadic Macros:: Macros with a variable number of arguments.
 * Escaped Newlines::    Slightly looser rules for escaped newlines.
@@ -1873,6 +1875,38 @@ The structure has size zero.  In C++, empty 
structures are part

 of the language.  G++ treats empty structures as if they had a single
 member of type @code{char}.
 +@node Flexible Array Members in Unions
+@section Unions with Flexible Array Members
+@cindex unions with flexible array members
+@cindex unions with FAMs
+
+GCC permits a C99 flexible array member (FAM) to be in a union:
+
+@smallexample
+union with_fam @{
+  int a;
+  int b[];
+@};
+@end smallexample
+
+If all the members of a union are flexible array member, the size of


It’s for the following case:

union with_fam_3 {
  char a[];
  int b[];
}

And also include:  (the only member of a union is a flexible array 
member as you mentioned below)


union with_fam_1 {
  char a[];
}

So, I think the original sentence:

“If all the members of a union are flexible array member, the size of”

Should be better than the below:


"If the only member of a union is a flexible array member”


How about the following wording?

"If every member of a union is flexible array member, the size of”


"is a flexible array member", sure.

Jason



Re: [PATCH v3 1/4] Allow flexible array members in unions and alone in structures [PR53548]

2024-04-30 Thread Jason Merrill

On 4/30/24 14:45, Qing Zhao wrote:




On Apr 30, 2024, at 15:27, Jason Merrill  wrote:

On 4/30/24 07:58, Qing Zhao wrote:

The request for GCC to accept that the C99 flexible array member can be
in a union or alone in a structure has been made a long time ago 
around 2012

for supporting several practical cases including glibc.
A GCC PR has been opened for such request at that time:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53548
However, this PR was closed as WONTFIX around 2015 due to the 
following reason:
"there is an existing extension that makes the requested 
functionality possible"
i.e GCC fully supported that the zero-length array can be in a union 
or alone
in a structure for a long time. (though I didn't see any official 
documentation

on such extension)
It's reasonable to close PR53548 at that time since zero-length array 
extension

can be used for such purpose.
However, since GCC13, in order to improve the C/C++ security, we 
introduced

-fstrict-flex-arrays=n to gradually eliminate the "fake flexible array"
usages from C/C++ source code. As a result, zero-length arrays eventually
will be replaced by C99 flexiable array member completely.
Therefore, GCC needs to explicitly allow such extensions directly for C99
flexible arrays, since flexable array member in unions or alone in 
structs
are common code patterns in active use by the Linux kernel (and other 
projects).

For example, these do not error by default with GCC:
union one {
  int a;
  int b[0];
};
union two {
  int a;
  struct {
struct { } __empty;
int b[];
  };
};
But these do:
union three {
  int a;
  int b[];
};
struct four {
  int b[];
}
Clang has supported such extensions since March, 2024
https://github.com/llvm/llvm-project/pull/84428
GCC should also support such extensions. This will allow for
a seamless transition for code bases away from zero-length arrays without
losing existing code patterns.
gcc/ChangeLog:
* doc/extend.texi: Add documentation for Flexible Array Members in
Unions and Flexible Array Members alone in Structures.
---
 gcc/doc/extend.texi | 34 ++
 1 file changed, 34 insertions(+)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7b54a241a7bf..cba98c8aadd7 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -42,6 +42,8 @@ extensions, accepted by GCC in C90 mode and in C++.
 * Named Address Spaces::Named address spaces.
 * Zero Length:: Zero-length arrays.
 * Empty Structures::    Structures with no members.
+* Flexible Array Members in Unions::  Unions with Flexible Array 
Members.
+* Flexible Array Members alone in Structures::  Structures with only 
Flexible Array Members.

 * Variable Length:: Arrays whose length is computed at run time.
 * Variadic Macros:: Macros with a variable number of arguments.
 * Escaped Newlines::    Slightly looser rules for escaped newlines.
@@ -1873,6 +1875,38 @@ The structure has size zero.  In C++, empty 
structures are part

 of the language.  G++ treats empty structures as if they had a single
 member of type @code{char}.
 +@node Flexible Array Members in Unions
+@section Unions with Flexible Array Members
+@cindex unions with flexible array members
+@cindex unions with FAMs
+
+GCC permits a C99 flexible array member (FAM) to be in a union:
+
+@smallexample
+union with_fam @{
+  int a;
+  int b[];
+@};
+@end smallexample
+
+If all the members of a union are flexible array member, the size of


It’s for the following case:

union with_fam_3 {
   char a[];
   int b[];
}

And also include:  (the only member of a union is a flexible array 
member as you mentioned below)


union with_fam_1 {
   char a[];
}

So, I think the original sentence:

“If all the members of a union are flexible array member, the size of”

Should be better than the below:


"If the only member of a union is a flexible array member”


Makes sense, but then it should be "members" both times rather than 
"members" and then "member".


Jason



Re: [PATCH v3 4/4] Update the C FE routine "add_flexible_array_elts_to_size" C++ FE routine "layout_var_decl" to handle the cases when the DECL is union.

2024-04-30 Thread Jason Merrill

On 4/30/24 07:58, Qing Zhao wrote:

Add testing cases to test the _bos for flexible array members in unions
or alone in structures.

gcc/c/ChangeLog:

* c-decl.cc (add_flexible_array_elts_to_size): Handle the cases
when the DECL is union.

gcc/cp/ChangeLog:

* decl.cc (layout_var_decl): Handle the cases when the DECL is
union with a flexible array member initializer.

gcc/testsuite/ChangeLog:

* c-c++-common/fam-in-union-alone-in-struct-bos-1.c: New test.
* c-c++-common/fam-in-union-alone-in-struct-bos.c: New test.
---
  gcc/c/c-decl.cc   | 32 +++--
  gcc/cp/decl.cc| 33 --
  .../fam-in-union-alone-in-struct-bos-1.c  | 66 +++
  .../fam-in-union-alone-in-struct-bos.c| 45 +
  4 files changed, 162 insertions(+), 14 deletions(-)
  create mode 100644 
gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos-1.c
  create mode 100644 
gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 947f3cd589eb..59302c5cfb1f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5337,9 +5337,9 @@ zero_length_array_type_p (const_tree type)
  }
  
  /* INIT is a constructor that forms DECL's initializer.  If the final

-   element initializes a flexible array field, add the size of that
-   initializer to DECL's size.  */
-
+   element initializes a flexible array field, adjust the size of the
+   DECL with the initializer based on whether the DECL is a union or
+   a structure.  */
  static void
  add_flexible_array_elts_to_size (tree decl, tree init)
  {
@@ -5348,15 +5348,33 @@ add_flexible_array_elts_to_size (tree decl, tree init)
if (vec_safe_is_empty (CONSTRUCTOR_ELTS (init)))
  return;
  
+  bool is_decl_type_union = (TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE);


In both C and C++ front-ends, I don't see any reason for this variable 
to be declared outside the if, since it's only used inside it.


It's not clear to me that it's needed at all since it's only used once, 
but if you prefer to have it, please move it inside the if.



+
elt = CONSTRUCTOR_ELTS (init)->last ().value;
type = TREE_TYPE (elt);
if (flexible_array_member_type_p (type))
  {
complete_array_type (, elt, false);
-  DECL_SIZE (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
-  DECL_SIZE_UNIT (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type));
+  /* For a structure, add the size of the initializer to the DECL's
+size.  */
+  if (!is_decl_type_union)
+   {
+ DECL_SIZE (decl)
+   = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
+ DECL_SIZE_UNIT (decl)
+   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl),
+ TYPE_SIZE_UNIT (type));
+   }
+  /* For a union, the DECL's size is the maximum of the current size
+and the size of the initializer.  */
+  else
+   {
+ DECL_SIZE (decl)
+   = size_binop (MAX_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
+ DECL_SIZE_UNIT (decl)
+   = size_binop (MAX_EXPR, DECL_SIZE_UNIT (decl),
+ TYPE_SIZE_UNIT (type));
+   }
  }
  }
  
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9a91c6f80da1..0ea3ef165b66 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6555,8 +6555,9 @@ layout_var_decl (tree decl)
}
  }
  
-  /* If the final element initializes a flexible array field, add the size of

- that initializer to DECL's size.  */
+  /* If the final element initializes a flexible array field, adjust
+ the size of the DECL with the initializer based on whether the
+ DECL is a union or a structure.  */
if (type != error_mark_node
&& DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR
@@ -6568,6 +6569,7 @@ layout_var_decl (tree decl)
&& tree_int_cst_equal (DECL_SIZE (decl), TYPE_SIZE (type)))
  {
constructor_elt  = CONSTRUCTOR_ELTS (DECL_INITIAL (decl))->last ();
+  bool is_decl_type_union = (TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE);
if (elt.index)
{
  tree itype = TREE_TYPE (elt.index);
@@ -6577,11 +6579,28 @@ layout_var_decl (tree decl)
  && TREE_CODE (vtype) == ARRAY_TYPE
  && COMPLETE_TYPE_P (vtype))
{
- DECL_SIZE (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (vtype));
- DECL_SIZE_UNIT (decl)
-   = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl),
- TYPE_SIZE_UNIT (vtype));
+ /* For a structure, add the size of the initializer to the DECL's
+size.  */
+ if (!is_decl_type_union)
+   {
+ DECL_SIZE (decl)
+   = size_binop 

Re: [PATCH v3 1/4] Allow flexible array members in unions and alone in structures [PR53548]

2024-04-30 Thread Jason Merrill

On 4/30/24 07:58, Qing Zhao wrote:

The request for GCC to accept that the C99 flexible array member can be
in a union or alone in a structure has been made a long time ago around 2012
for supporting several practical cases including glibc.

A GCC PR has been opened for such request at that time:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53548

However, this PR was closed as WONTFIX around 2015 due to the following reason:

"there is an existing extension that makes the requested functionality possible"
i.e GCC fully supported that the zero-length array can be in a union or alone
in a structure for a long time. (though I didn't see any official documentation
on such extension)

It's reasonable to close PR53548 at that time since zero-length array extension
can be used for such purpose.

However, since GCC13, in order to improve the C/C++ security, we introduced
-fstrict-flex-arrays=n to gradually eliminate the "fake flexible array"
usages from C/C++ source code. As a result, zero-length arrays eventually
will be replaced by C99 flexiable array member completely.

Therefore, GCC needs to explicitly allow such extensions directly for C99
flexible arrays, since flexable array member in unions or alone in structs
are common code patterns in active use by the Linux kernel (and other projects).

For example, these do not error by default with GCC:

union one {
   int a;
   int b[0];
};

union two {
   int a;
   struct {
 struct { } __empty;
 int b[];
   };
};

But these do:

union three {
   int a;
   int b[];
};

struct four {
   int b[];
}

Clang has supported such extensions since March, 2024
https://github.com/llvm/llvm-project/pull/84428

GCC should also support such extensions. This will allow for
a seamless transition for code bases away from zero-length arrays without
losing existing code patterns.

gcc/ChangeLog:

* doc/extend.texi: Add documentation for Flexible Array Members in
Unions and Flexible Array Members alone in Structures.
---
  gcc/doc/extend.texi | 34 ++
  1 file changed, 34 insertions(+)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7b54a241a7bf..cba98c8aadd7 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -42,6 +42,8 @@ extensions, accepted by GCC in C90 mode and in C++.
  * Named Address Spaces::Named address spaces.
  * Zero Length:: Zero-length arrays.
  * Empty Structures::Structures with no members.
+* Flexible Array Members in Unions::  Unions with Flexible Array Members.
+* Flexible Array Members alone in Structures::  Structures with only Flexible 
Array Members.
  * Variable Length:: Arrays whose length is computed at run time.
  * Variadic Macros:: Macros with a variable number of arguments.
  * Escaped Newlines::Slightly looser rules for escaped newlines.
@@ -1873,6 +1875,38 @@ The structure has size zero.  In C++, empty structures 
are part
  of the language.  G++ treats empty structures as if they had a single
  member of type @code{char}.
  
+@node Flexible Array Members in Unions

+@section Unions with Flexible Array Members
+@cindex unions with flexible array members
+@cindex unions with FAMs
+
+GCC permits a C99 flexible array member (FAM) to be in a union:
+
+@smallexample
+union with_fam @{
+  int a;
+  int b[];
+@};
+@end smallexample
+
+If all the members of a union are flexible array member, the size of


"If the only member of a union is a flexible array member"


+such union is zero.


"such a union"


+
+@node Flexible Array Members alone in Structures
+@section Structures with only Flexible Array Members
+@cindex structures with only flexible array members
+@cindex structures with only FAMs
+
+GCC permits a C99 flexible array member (FAM) to be alone in a structure:
+
+@smallexample
+struct only_fam @{
+  int b[];
+@};
+@end smallexample
+
+The size of such structure gives the size zero.


"The size of such a structure is zero"


+
  @node Variable Length
  @section Arrays of Variable Length
  @cindex variable-length arrays




Re: [PATCH v14 25/26] c++: Implement __is_nothrow_invocable built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::is_nothrow_invocable.


OK after addressing comments on other traits.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_nothrow_invocable.
* constraint.cc (diagnose_trait_expr): Handle
CPTK_IS_NOTHROW_INVOCABLE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of
__is_nothrow_invocable.
* g++.dg/ext/is_nothrow_invocable.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc  |  6 ++
  gcc/cp/cp-trait.def   |  1 +
  gcc/cp/semantics.cc   |  4 ++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 +
  .../g++.dg/ext/is_nothrow_invocable.C | 62 +++
  5 files changed, 76 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_nothrow_invocable.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c87b126fdb1..43d4f2102d6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3824,6 +3824,12 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_NOTHROW_CONVERTIBLE:
  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
break;
+case CPTK_IS_NOTHROW_INVOCABLE:
+   if (!t2)
+ inform (loc, "  %qT is not nothrow invocable", t1);
+   else
+ inform (loc, "  %qT is not nothrow invocable by %qE", t1, t2);
+   break;
  case CPTK_IS_OBJECT:
inform (loc, "  %qT is not an object type", t1);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6cb2b55f4ea..a9714921e94 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,6 +84,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
  DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
  DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
  DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
+DEFTRAIT_EXPR (IS_NOTHROW_INVOCABLE, "__is_nothrow_invocable", -1)
  DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
  DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, 
"__is_pointer_interconvertible_base_of", 2)
  DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 149c0631d62..dba7b43a109 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12494,6 +12494,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_NOTHROW_CONVERTIBLE:
return is_nothrow_convertible (type1, type2);
  
+case CPTK_IS_NOTHROW_INVOCABLE:

+  return expr_noexcept_p (build_invoke (type1, type2, tf_none), tf_none);
+
  case CPTK_IS_OBJECT:
return (type_code1 != FUNCTION_TYPE
  && type_code1 != REFERENCE_TYPE
@@ -12689,6 +12692,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, 
tree type1, tree type2)
  case CPTK_IS_NOTHROW_ASSIGNABLE:
  case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
  case CPTK_IS_NOTHROW_CONVERTIBLE:
+case CPTK_IS_NOTHROW_INVOCABLE:
  case CPTK_IS_TRIVIALLY_ASSIGNABLE:
  case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
  case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index d2a7ebdf25c..624d3525f27 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
  #if !__has_builtin (__is_nothrow_convertible)
  # error "__has_builtin (__is_nothrow_convertible) failed"
  #endif
+#if !__has_builtin (__is_nothrow_invocable)
+# error "__has_builtin (__is_nothrow_invocable) failed"
+#endif
  #if !__has_builtin (__is_object)
  # error "__has_builtin (__is_object) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_invocable.C 
b/gcc/testsuite/g++.dg/ext/is_nothrow_invocable.C
new file mode 100644
index 000..2f9b40e5538
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_nothrow_invocable.C
@@ -0,0 +1,62 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+using func_type = void(*)();
+SA( ! __is_nothrow_invocable(func_type) );
+
+#if __cpp_noexcept_function_type
+using func_type_nt = void(*)() noexcept;
+SA(   __is_nothrow_invocable(func_type_nt) );
+#endif
+
+struct X { };
+using mem_type = int X::*;
+
+SA( ! __is_nothrow_invocable(mem_type) );
+SA( ! __is_nothrow_invocable(mem_type, int) );
+SA( ! __is_nothrow_invocable(mem_type, int&) );
+SA(   __is_nothrow_invocable(mem_type, X&) );
+
+using memfun_type = int (X::*)();
+
+SA( ! __is_nothrow_invocable(memfun_type) );
+SA( ! __is_nothrow_invocable(memfun_type, int) );
+SA( ! __is_nothrow_invocable(memfun_type, int&) );
+SA( ! __is_nothrow_invocable(memfun_type, X&) );
+SA( ! __is_nothrow_invocable(memfun_type, X*) );
+
+#if __cpp_noexcept_function_type

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

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::rank.


__rank seems too short, maybe __array_rank?

Actually, it occurs to me that perhaps we should have been adding 
__builtin to all of these rather than just __ and the library trait 
name.  I guess it's too late to do that for the GCC 14 traits, but we 
could do it for this group?



gcc/cp/ChangeLog:

* cp-trait.def: Define __rank.
* constraint.cc (diagnose_trait_expr): Handle CPTK_RANK.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __rank.
* g++.dg/ext/rank.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 +++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  | 23 ---
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  gcc/testsuite/g++.dg/ext/rank.C  | 24 
  5 files changed, 51 insertions(+), 3 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/ext/rank.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 000df847342..23ea66d9c12 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3870,6 +3870,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_VOLATILE:
inform (loc, "  %qT is not a volatile type", t1);
break;
+case CPTK_RANK:
+  inform (loc, "  %qT cannot yield a rank", t1);
+  break;
  case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
inform (loc, "  %qT is not a reference that binds to a temporary "
  "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2d1cb7c227c..85056c8140b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -99,6 +99,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, 
"__is_trivially_copyable", 1)
  DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
  DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
+DEFTRAIT_EXPR (RANK, "__rank", 1)
  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
"__reference_constructs_from_temporary", 2)
  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
"__reference_converts_from_temporary", 2)
  DEFTRAIT_TYPE (REMOVE_ALL_EXTENTS, "__remove_all_extents", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 45dc509855a..7242db75248 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12550,6 +12550,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_DEDUCIBLE:
return type_targs_deducible_from (type1, type2);
  
+/* __rank is handled in finish_trait_expr. */

+case CPTK_RANK:


This should have a gcc_unreachable.


+
  #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
  case CPTK_##CODE:
  #include "cp-trait.def"
@@ -12622,7 +12625,10 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, 
tree type1, tree type2)
if (processing_template_decl)
  {
tree trait_expr = make_node (TRAIT_EXPR);
-  TREE_TYPE (trait_expr) = boolean_type_node;
+  if (kind == CPTK_RANK)
+   TREE_TYPE (trait_expr) = size_type_node;
+  else
+   TREE_TYPE (trait_expr) = boolean_type_node;
TRAIT_EXPR_TYPE1 (trait_expr) = type1;
TRAIT_EXPR_TYPE2 (trait_expr) = type2;
TRAIT_EXPR_KIND (trait_expr) = kind;
@@ -12714,6 +12720,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, 
tree type1, tree type2)
  case CPTK_IS_UNBOUNDED_ARRAY:
  case CPTK_IS_UNION:
  case CPTK_IS_VOLATILE:
+case CPTK_RANK:
break;
  
  case CPTK_IS_LAYOUT_COMPATIBLE:

@@ -12745,8 +12752,18 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, 
tree type1, tree type2)
gcc_unreachable ();
  }
  
-  tree val = (trait_expr_value (kind, type1, type2)

- ? boolean_true_node : boolean_false_node);
+  tree val;
+  if (kind == CPTK_RANK)
+{
+  size_t rank = 0;
+  for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
+   ++rank;
+  val = build_int_cst (size_type_node, rank);
+}
+  else
+val = (trait_expr_value (kind, type1, type2)
+  ? boolean_true_node : boolean_false_node);
+
return maybe_wrap_with_location (val, loc);
  }
  
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C

index 3aca273aad6..7f7b27f7aa7 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -179,6 +179,9 @@
  #if !__has_builtin (__is_volatile)
  # error "__has_builtin (__is_volatile) failed"
  #endif
+#if !__has_builtin (__rank)
+# error "__has_builtin (__rank) failed"
+#endif
  #if !__has_builtin (__reference_constructs_from_temporary)
  # error "__has_builtin (__reference_constructs_from_temporary) failed"
  #endif
diff --git 

Re: [PATCH v14 19/26] c++: Implement __decay built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::decay.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __decay.
* semantics.cc (finish_trait_type): Handle CPTK_DECAY.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __decay.
* g++.dg/ext/decay.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  | 12 
  gcc/testsuite/g++.dg/ext/decay.C | 22 ++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  4 files changed, 38 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/decay.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 173818adf79..2d1cb7c227c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -51,6 +51,7 @@
  DEFTRAIT_TYPE (ADD_LVALUE_REFERENCE, "__add_lvalue_reference", 1)
  DEFTRAIT_TYPE (ADD_POINTER, "__add_pointer", 1)
  DEFTRAIT_TYPE (ADD_RVALUE_REFERENCE, "__add_rvalue_reference", 1)
+DEFTRAIT_TYPE (DECAY, "__decay", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 19d6f87a9ea..45dc509855a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12801,6 +12801,18 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
tree type2,
return type1;
return cp_build_reference_type (type1, /*rval=*/true);
  
+case CPTK_DECAY:

+  if (TYPE_REF_P (type1))
+   type1 = TREE_TYPE (type1);
+
+  if (TREE_CODE (type1) == ARRAY_TYPE)
+   return finish_trait_type (CPTK_ADD_POINTER, TREE_TYPE (type1), type2,
+ complain);
+  else if (TREE_CODE (type1) == FUNCTION_TYPE)
+   return finish_trait_type (CPTK_ADD_POINTER, type1, type2, complain);
+  else
+   return cv_unqualified (type1);
+
  case CPTK_REMOVE_ALL_EXTENTS:
return strip_array_types (type1);
  
diff --git a/gcc/testsuite/g++.dg/ext/decay.C b/gcc/testsuite/g++.dg/ext/decay.C

new file mode 100644
index 000..8adedfeefe6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/decay.C
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+using test1_type = __decay(bool);
+SA(__is_same(test1_type, bool));
+
+// NB: DR 705.
+using test2_type = __decay(const int);
+SA(__is_same(test2_type, int));
+
+using test3_type = __decay(int[4]);
+SA(__is_same(test3_type, __remove_extent(int[4])*));
+
+using fn_type = void ();
+using test4_type = __decay(fn_type);
+SA(__is_same(test4_type, __add_pointer(fn_type)));
+
+using cfn_type = void () const;
+using test5_type = __decay(cfn_type);
+SA(__is_same(test5_type, cfn_type));
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index c2503c5d82b..3aca273aad6 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -11,6 +11,9 @@
  #if !__has_builtin (__add_rvalue_reference)
  # error "__has_builtin (__add_rvalue_reference) failed"
  #endif
+#if !__has_builtin (__decay)
+# error "__has_builtin (__decay) failed"
+#endif
  #if !__has_builtin (__builtin_addressof)
  # error "__has_builtin (__builtin_addressof) failed"
  #endif




Re: [PATCH v14 17/26] c++: Implement __add_rvalue_reference built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::add_rvalue_reference.

gcc/cp/ChangeLog:

* cp-trait.def: Define __add_rvalue_reference.
* semantics.cc (finish_trait_type): Handle
CPTK_ADD_RVALUE_REFERENCE.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of
__add_rvalue_reference.
* g++.dg/ext/add_rvalue_reference.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/cp-trait.def   |  1 +
  gcc/cp/semantics.cc   |  8 
  .../g++.dg/ext/add_rvalue_reference.C | 20 +++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 +++
  4 files changed, 32 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/add_rvalue_reference.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9a27dca4ea3..173818adf79 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -50,6 +50,7 @@
  
  DEFTRAIT_TYPE (ADD_LVALUE_REFERENCE, "__add_lvalue_reference", 1)

  DEFTRAIT_TYPE (ADD_POINTER, "__add_pointer", 1)
+DEFTRAIT_TYPE (ADD_RVALUE_REFERENCE, "__add_rvalue_reference", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 05f5b62f9df..19d6f87a9ea 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12793,6 +12793,14 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
tree type2,
type1 = TREE_TYPE (type1);
return build_pointer_type (type1);
  
+case CPTK_ADD_RVALUE_REFERENCE:

+  if (VOID_TYPE_P (type1)
+ || (FUNC_OR_METHOD_TYPE_P (type1)
+ && (type_memfn_quals (type1) != TYPE_UNQUALIFIED
+ || type_memfn_rqual (type1) != REF_QUAL_NONE)))


Actually, let's factor this bit out of this and the other traits into a 
referenceable_type_p function since it's getting checked so much.



+   return type1;
+  return cp_build_reference_type (type1, /*rval=*/true);
+
  case CPTK_REMOVE_ALL_EXTENTS:
return strip_array_types (type1);
  
diff --git a/gcc/testsuite/g++.dg/ext/add_rvalue_reference.C b/gcc/testsuite/g++.dg/ext/add_rvalue_reference.C

new file mode 100644
index 000..c92fe6bfa17
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/add_rvalue_reference.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+
+SA(__is_same(__add_rvalue_reference(int), int&&));
+SA(__is_same(__add_rvalue_reference(int&&), int&&));
+SA(__is_same(__add_rvalue_reference(int&), int&));
+SA(__is_same(__add_rvalue_reference(const int), const int&&));
+SA(__is_same(__add_rvalue_reference(int*), int*&&));
+SA(__is_same(__add_rvalue_reference(ClassType&&), ClassType&&));
+SA(__is_same(__add_rvalue_reference(ClassType), ClassType&&));
+SA(__is_same(__add_rvalue_reference(int(int)), int(&&)(int)));
+SA(__is_same(__add_rvalue_reference(void), void));
+SA(__is_same(__add_rvalue_reference(const void), const void));
+SA(__is_same(__add_rvalue_reference(bool(int) const), bool(int) const));
+SA(__is_same(__add_rvalue_reference(bool(int) &), bool(int) &));
+SA(__is_same(__add_rvalue_reference(bool(int) const &&), bool(int) const &&));
+SA(__is_same(__add_rvalue_reference(bool(int)), bool(&&)(int)));
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3fca9cfabcc..c2503c5d82b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,6 +8,9 @@
  #if !__has_builtin (__add_pointer)
  # error "__has_builtin (__add_pointer) failed"
  #endif
+#if !__has_builtin (__add_rvalue_reference)
+# error "__has_builtin (__add_rvalue_reference) failed"
+#endif
  #if !__has_builtin (__builtin_addressof)
  # error "__has_builtin (__builtin_addressof) failed"
  #endif




Re: [PATCH v14 15/26] c++: Implement __add_lvalue_reference built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::add_lvalue_reference.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __add_lvalue_reference.
* semantics.cc (finish_trait_type): Handle
CPTK_ADD_LVALUE_REFERENCE.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of
__add_lvalue_reference.
* g++.dg/ext/add_lvalue_reference.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/cp-trait.def   |  1 +
  gcc/cp/semantics.cc   |  8 +++
  .../g++.dg/ext/add_lvalue_reference.C | 21 +++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 +++
  4 files changed, 33 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/add_lvalue_reference.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 933c8bcbe68..9a27dca4ea3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -48,6 +48,7 @@
  #define DEFTRAIT_TYPE_DEFAULTED
  #endif
  
+DEFTRAIT_TYPE (ADD_LVALUE_REFERENCE, "__add_lvalue_reference", 1)

  DEFTRAIT_TYPE (ADD_POINTER, "__add_pointer", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 078424dac23..05f5b62f9df 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12776,6 +12776,14 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
tree type2,
  
switch (kind)

  {
+case CPTK_ADD_LVALUE_REFERENCE:
+  if (VOID_TYPE_P (type1)
+ || (FUNC_OR_METHOD_TYPE_P (type1)
+ && (type_memfn_quals (type1) != TYPE_UNQUALIFIED
+ || type_memfn_rqual (type1) != REF_QUAL_NONE)))
+   return type1;
+  return cp_build_reference_type (type1, /*rval=*/false);
+
  case CPTK_ADD_POINTER:
if (FUNC_OR_METHOD_TYPE_P (type1)
  && (type_memfn_quals (type1) != TYPE_UNQUALIFIED
diff --git a/gcc/testsuite/g++.dg/ext/add_lvalue_reference.C 
b/gcc/testsuite/g++.dg/ext/add_lvalue_reference.C
new file mode 100644
index 000..8fe1e0300e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/add_lvalue_reference.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+
+SA(__is_same(__add_lvalue_reference(int), int&));
+SA(__is_same(__add_lvalue_reference(int&), int&));
+SA(__is_same(__add_lvalue_reference(const int), const int&));
+SA(__is_same(__add_lvalue_reference(int*), int*&));
+SA(__is_same(__add_lvalue_reference(ClassType&), ClassType&));
+SA(__is_same(__add_lvalue_reference(ClassType), ClassType&));
+SA(__is_same(__add_lvalue_reference(int(int)), int(&)(int)));
+SA(__is_same(__add_lvalue_reference(int&&), int&));
+SA(__is_same(__add_lvalue_reference(ClassType&&), ClassType&));
+SA(__is_same(__add_lvalue_reference(void), void));
+SA(__is_same(__add_lvalue_reference(const void), const void));
+SA(__is_same(__add_lvalue_reference(bool(int) const), bool(int) const));
+SA(__is_same(__add_lvalue_reference(bool(int) &), bool(int) &));
+SA(__is_same(__add_lvalue_reference(bool(int) const &&), bool(int) const &&));
+SA(__is_same(__add_lvalue_reference(bool(int)), bool(&)(int)));
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 85b74bd676b..3fca9cfabcc 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -2,6 +2,9 @@
  // { dg-do compile }
  // Verify that __has_builtin gives the correct answer for C++ built-ins.
  
+#if !__has_builtin (__add_lvalue_reference)

+# error "__has_builtin (__add_lvalue_reference) failed"
+#endif
  #if !__has_builtin (__add_pointer)
  # error "__has_builtin (__add_pointer) failed"
  #endif




Re: [PATCH v14 11/26] c++: Implement __remove_extent built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::remove_extent.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __remove_extent.
* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_EXTENT.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __remove_extent.
* g++.dg/ext/remove_extent.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  5 +
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  gcc/testsuite/g++.dg/ext/remove_extent.C | 16 
  4 files changed, 25 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/remove_extent.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 63f879287ce..577c96d579b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -100,6 +100,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
"__reference_constructs_from_tempo
  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
"__reference_converts_from_temporary", 2)
  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1)
  DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
  DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 635441a7a90..58696225fc4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12793,6 +12793,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
tree type2,
type1 = TREE_TYPE (type1);
return cv_unqualified (type1);
  
+case CPTK_REMOVE_EXTENT:

+  if (TREE_CODE (type1) == ARRAY_TYPE)
+   type1 = TREE_TYPE (type1);
+  return type1;
+
  case CPTK_REMOVE_POINTER:
if (TYPE_PTR_P (type1))
type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 9d861398bae..5d5cbe3b019 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -182,6 +182,9 @@
  #if !__has_builtin (__remove_cvref)
  # error "__has_builtin (__remove_cvref) failed"
  #endif
+#if !__has_builtin (__remove_extent)
+# error "__has_builtin (__remove_extent) failed"
+#endif
  #if !__has_builtin (__remove_pointer)
  # error "__has_builtin (__remove_pointer) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_extent.C 
b/gcc/testsuite/g++.dg/ext/remove_extent.C
new file mode 100644
index 000..6183aca5a48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_extent.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+
+SA(__is_same(__remove_extent(int), int));
+SA(__is_same(__remove_extent(int[2]), int));
+SA(__is_same(__remove_extent(int[2][3]), int[3]));
+SA(__is_same(__remove_extent(int[][3]), int[3]));
+SA(__is_same(__remove_extent(const int[2]), const int));
+SA(__is_same(__remove_extent(ClassType), ClassType));
+SA(__is_same(__remove_extent(ClassType[2]), ClassType));
+SA(__is_same(__remove_extent(ClassType[2][3]), ClassType[3]));
+SA(__is_same(__remove_extent(ClassType[][3]), ClassType[3]));
+SA(__is_same(__remove_extent(const ClassType[2]), const ClassType));




Re: [PATCH v14 13/26] c++: Implement __remove_all_extents built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::remove_all_extents.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __remove_all_extents.
* semantics.cc (finish_trait_type): Handle
CPTK_REMOVE_ALL_EXTENTS.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of
__remove_all_extents.
* g++.dg/ext/remove_all_extents.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/cp-trait.def   |  1 +
  gcc/cp/semantics.cc   |  3 +++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 +++
  gcc/testsuite/g++.dg/ext/remove_all_extents.C | 16 
  4 files changed, 23 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/remove_all_extents.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 577c96d579b..933c8bcbe68 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -98,6 +98,7 @@ DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
  DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
"__reference_constructs_from_temporary", 2)
  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
"__reference_converts_from_temporary", 2)
+DEFTRAIT_TYPE (REMOVE_ALL_EXTENTS, "__remove_all_extents", 1)
  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
  DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 58696225fc4..078424dac23 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12785,6 +12785,9 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree 
type2,
type1 = TREE_TYPE (type1);
return build_pointer_type (type1);
  
+case CPTK_REMOVE_ALL_EXTENTS:

+  return strip_array_types (type1);
+
  case CPTK_REMOVE_CV:
return cv_unqualified (type1);
  
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C

index 5d5cbe3b019..85b74bd676b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -176,6 +176,9 @@
  #if !__has_builtin (__reference_converts_from_temporary)
  # error "__has_builtin (__reference_converts_from_temporary) failed"
  #endif
+#if !__has_builtin (__remove_all_extents)
+# error "__has_builtin (__remove_all_extents) failed"
+#endif
  #if !__has_builtin (__remove_cv)
  # error "__has_builtin (__remove_cv) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_all_extents.C 
b/gcc/testsuite/g++.dg/ext/remove_all_extents.C
new file mode 100644
index 000..60ade2ade7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_all_extents.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+
+SA(__is_same(__remove_all_extents(int), int));
+SA(__is_same(__remove_all_extents(int[2]), int));
+SA(__is_same(__remove_all_extents(int[2][3]), int));
+SA(__is_same(__remove_all_extents(int[][3]), int));
+SA(__is_same(__remove_all_extents(const int[2][3]), const int));
+SA(__is_same(__remove_all_extents(ClassType), ClassType));
+SA(__is_same(__remove_all_extents(ClassType[2]), ClassType));
+SA(__is_same(__remove_all_extents(ClassType[2][3]), ClassType));
+SA(__is_same(__remove_all_extents(ClassType[][3]), ClassType));
+SA(__is_same(__remove_all_extents(const ClassType[2][3]), const ClassType));




Re: [PATCH v14 09/26] c++: Implement __add_pointer built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::add_pointer.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __add_pointer.
* semantics.cc (finish_trait_type): Handle CPTK_ADD_POINTER.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __add_pointer.
* g++.dg/ext/add_pointer.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  9 ++
  gcc/testsuite/g++.dg/ext/add_pointer.C   | 39 
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
  4 files changed, 52 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/add_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 05514a51c21..63f879287ce 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -48,6 +48,7 @@
  #define DEFTRAIT_TYPE_DEFAULTED
  #endif
  
+DEFTRAIT_TYPE (ADD_POINTER, "__add_pointer", 1)

  DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1)
  DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 1794e83baa2..635441a7a90 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12776,6 +12776,15 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
tree type2,
  
switch (kind)

  {
+case CPTK_ADD_POINTER:
+  if (FUNC_OR_METHOD_TYPE_P (type1)
+ && (type_memfn_quals (type1) != TYPE_UNQUALIFIED
+ || type_memfn_rqual (type1) != REF_QUAL_NONE))
+   return type1;
+  if (TYPE_REF_P (type1))
+   type1 = TREE_TYPE (type1);
+  return build_pointer_type (type1);
+
  case CPTK_REMOVE_CV:
return cv_unqualified (type1);
  
diff --git a/gcc/testsuite/g++.dg/ext/add_pointer.C b/gcc/testsuite/g++.dg/ext/add_pointer.C

new file mode 100644
index 000..c405cdd0feb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/add_pointer.C
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+
+SA(__is_same(__add_pointer(int), int*));
+SA(__is_same(__add_pointer(int*), int**));
+SA(__is_same(__add_pointer(const int), const int*));
+SA(__is_same(__add_pointer(int&), int*));
+SA(__is_same(__add_pointer(ClassType*), ClassType**));
+SA(__is_same(__add_pointer(ClassType), ClassType*));
+SA(__is_same(__add_pointer(void), void*));
+SA(__is_same(__add_pointer(const void), const void*));
+SA(__is_same(__add_pointer(volatile void), volatile void*));
+SA(__is_same(__add_pointer(const volatile void), const volatile void*));
+
+void f1();
+using f1_type = decltype(f1);
+using pf1_type = decltype();
+SA(__is_same(__add_pointer(f1_type), pf1_type));
+
+void f2() noexcept; // PR libstdc++/78361
+using f2_type = decltype(f2);
+using pf2_type = decltype();
+SA(__is_same(__add_pointer(f2_type), pf2_type));
+
+using fn_type = void();
+using pfn_type = void(*)();
+SA(__is_same(__add_pointer(fn_type), pfn_type));
+
+SA(__is_same(__add_pointer(void() &), void() &));
+SA(__is_same(__add_pointer(void() & noexcept), void() & noexcept));
+SA(__is_same(__add_pointer(void() const), void() const));
+SA(__is_same(__add_pointer(void(...) &), void(...) &));
+SA(__is_same(__add_pointer(void(...) & noexcept), void(...) & noexcept));
+SA(__is_same(__add_pointer(void(...) const), void(...) const));
+
+SA(__is_same(__add_pointer(void() __restrict), void() __restrict));
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b1430e9bd8b..9d861398bae 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -2,6 +2,9 @@
  // { dg-do compile }
  // Verify that __has_builtin gives the correct answer for C++ built-ins.
  
+#if !__has_builtin (__add_pointer)

+# error "__has_builtin (__add_pointer) failed"
+#endif
  #if !__has_builtin (__builtin_addressof)
  # error "__has_builtin (__builtin_addressof) failed"
  #endif




Re: [PATCH v14 07/26] c++: Implement __is_unbounded_array built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::is_unbounded_array.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_unbounded_array.
* constraint.cc (diagnose_trait_expr): Handle
CPTK_IS_UNBOUNDED_ARRAY.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of
__is_unbounded_array.
* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc  |  3 ++
  gcc/cp/cp-trait.def   |  1 +
  gcc/cp/semantics.cc   |  4 ++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
  gcc/testsuite/g++.dg/ext/is_unbounded_array.C | 37 +++
  5 files changed, 48 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 244070d93c2..000df847342 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3861,6 +3861,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_TRIVIALLY_COPYABLE:
inform (loc, "  %qT is not trivially copyable", t1);
break;
+case CPTK_IS_UNBOUNDED_ARRAY:
+  inform (loc, "  %qT is not an unbounded array", t1);
+  break;
  case CPTK_IS_UNION:
inform (loc, "  %qT is not a union", t1);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 18e2d0f3480..05514a51c21 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -92,6 +92,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
  DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
  DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
"__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9dcdb06191a..1794e83baa2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12532,6 +12532,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_TRIVIALLY_COPYABLE:
return trivially_copyable_p (type1);
  
+case CPTK_IS_UNBOUNDED_ARRAY:

+  return array_of_unknown_bound_p (type1);
+
  case CPTK_IS_UNION:
return type_code1 == UNION_TYPE;
  
@@ -12708,6 +12711,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_REFERENCE:
  case CPTK_IS_SAME:
  case CPTK_IS_SCOPED_ENUM:
+case CPTK_IS_UNBOUNDED_ARRAY:
  case CPTK_IS_UNION:
  case CPTK_IS_VOLATILE:
break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 96b7a89e4f1..b1430e9bd8b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -158,6 +158,9 @@
  #if !__has_builtin (__is_trivially_copyable)
  # error "__has_builtin (__is_trivially_copyable) failed"
  #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
  #if !__has_builtin (__is_union)
  # error "__has_builtin (__is_union) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C 
b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 000..283a74e1a0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)  \
+  SA(TRAIT(TYPE) == EXPECT);   \
+  SA(TRAIT(const TYPE) == EXPECT); \
+  SA(TRAIT(volatile TYPE) == EXPECT);  \
+  SA(TRAIT(const volatile TYPE) == EXPECT)
+
+class ClassType { };
+class IncompleteClass;
+union IncompleteUnion;
+
+SA_TEST_CATEGORY(__is_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);

Re: [PATCH v14 05/26] c++: Implement __is_pointer built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::is_pointer.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_pointer.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 ++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  4 ++
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
  gcc/testsuite/g++.dg/ext/is_pointer.C| 51 
  5 files changed, 62 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9a7a12629e7..244070d93c2 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3828,6 +3828,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_POD:
inform (loc, "  %qT is not a POD type", t1);
break;
+case CPTK_IS_POINTER:
+  inform (loc, "  %qT is not a pointer", t1);
+  break;
  case CPTK_IS_POLYMORPHIC:
inform (loc, "  %qT is not a polymorphic type", t1);
break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e9347453829..18e2d0f3480 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -82,6 +82,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, 
"__is_nothrow_convertible", 2)
  DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
  DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, 
"__is_pointer_interconvertible_base_of", 2)
  DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
  DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
  DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
  DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 41c25f43d27..9dcdb06191a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12502,6 +12502,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_POD:
return pod_type_p (type1);
  
+case CPTK_IS_POINTER:

+  return TYPE_PTR_P (type1);
+
  case CPTK_IS_POLYMORPHIC:
return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
  
@@ -12701,6 +12704,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_MEMBER_OBJECT_POINTER:
  case CPTK_IS_MEMBER_POINTER:
  case CPTK_IS_OBJECT:
+case CPTK_IS_POINTER:
  case CPTK_IS_REFERENCE:
  case CPTK_IS_SAME:
  case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b2e2f2f694d..96b7a89e4f1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -125,6 +125,9 @@
  #if !__has_builtin (__is_pod)
  # error "__has_builtin (__is_pod) failed"
  #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
  #if !__has_builtin (__is_polymorphic)
  # error "__has_builtin (__is_polymorphic) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C 
b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));

Re: [PATCH v14 03/26] c++: Implement __is_volatile built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::is_volatile.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_volatile.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 +++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  4 
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  gcc/testsuite/g++.dg/ext/is_volatile.C   | 20 
  5 files changed, 31 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f32a1c78d63..9a7a12629e7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3861,6 +3861,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_UNION:
inform (loc, "  %qT is not a union", t1);
break;
+case CPTK_IS_VOLATILE:
+  inform (loc, "  %qT is not a volatile type", t1);
+  break;
  case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
inform (loc, "  %qT is not a reference that binds to a temporary "
  "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 36faed9c0b3..e9347453829 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -92,6 +92,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, 
"__is_trivially_assignable", 2)
  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
"__reference_constructs_from_temporary", 2)
  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
"__reference_converts_from_temporary", 2)
  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0d08900492b..41c25f43d27 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12532,6 +12532,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_UNION:
return type_code1 == UNION_TYPE;
  
+case CPTK_IS_VOLATILE:

+  return CP_TYPE_VOLATILE_P (type1);
+
  case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
  
@@ -12702,6 +12705,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_SAME:
  case CPTK_IS_SCOPED_ENUM:
  case CPTK_IS_UNION:
+case CPTK_IS_VOLATILE:
break;
  
  case CPTK_IS_LAYOUT_COMPATIBLE:

diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e3640faeb96..b2e2f2f694d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -158,6 +158,9 @@
  #if !__has_builtin (__is_union)
  # error "__has_builtin (__is_union) failed"
  #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
  #if !__has_builtin (__reference_constructs_from_temporary)
  # error "__has_builtin (__reference_constructs_from_temporary) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C 
b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 000..80a1cfc880d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+using cClassType = const ClassType;
+using vClassType = volatile ClassType;
+using cvClassType = const volatile ClassType;
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));




Re: [PATCH v14 01/26] c++: Implement __is_const built-in trait

2024-04-30 Thread Jason Merrill

On 2/28/24 11:26, Ken Matsui wrote:

This patch implements built-in trait for std::is_const.


OK.


gcc/cp/ChangeLog:

* cp-trait.def: Define __is_const.
* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
* semantics.cc (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui 
---
  gcc/cp/constraint.cc |  3 +++
  gcc/cp/cp-trait.def  |  1 +
  gcc/cp/semantics.cc  |  4 
  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
  gcc/testsuite/g++.dg/ext/is_const.C  | 20 
  5 files changed, 31 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 49de3211d4c..f32a1c78d63 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3767,6 +3767,9 @@ diagnose_trait_expr (tree expr, tree args)
  case CPTK_IS_CLASS:
inform (loc, "  %qT is not a class", t1);
break;
+case CPTK_IS_CONST:
+  inform (loc, "  %qT is not a const type", t1);
+  break;
  case CPTK_IS_CONSTRUCTIBLE:
if (!t2)
  inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 394f006f20f..36faed9c0b3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -64,6 +64,7 @@ DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
  DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
  DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
  DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
  DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
  DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
  DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 57840176863..0d08900492b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12446,6 +12446,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree 
type2)
  case CPTK_IS_CLASS:
return NON_UNION_CLASS_TYPE_P (type1);
  
+case CPTK_IS_CONST:

+  return CP_TYPE_CONST_P (type1);
+
  case CPTK_IS_CONSTRUCTIBLE:
return is_xible (INIT_EXPR, type1, type2);
  
@@ -12688,6 +12691,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)

  case CPTK_IS_ARRAY:
  case CPTK_IS_BOUNDED_ARRAY:
  case CPTK_IS_CLASS:
+case CPTK_IS_CONST:
  case CPTK_IS_ENUM:
  case CPTK_IS_FUNCTION:
  case CPTK_IS_MEMBER_FUNCTION_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 02b4b4d745d..e3640faeb96 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -71,6 +71,9 @@
  #if !__has_builtin (__is_class)
  # error "__has_builtin (__is_class) failed"
  #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
  #if !__has_builtin (__is_constructible)
  # error "__has_builtin (__is_constructible) failed"
  #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C 
b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 000..8a0e8df72a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+class ClassType { };
+using cClassType = const ClassType;
+using vClassType = volatile ClassType;
+using cvClassType = const volatile ClassType;
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));




Re: [PATCH v15 23/26] c++: Implement __is_invocable built-in trait

2024-04-30 Thread Jason Merrill

On 3/15/24 01:15, Ken Matsui wrote:

Added diagnostics for build_invoke.

Ok for 15?


Thanks, just a few tweaks needed.  Will you have time to make them?  Or 
Patrick?


[...]

diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 98c10e6a8b5..2282ce71c06 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1928,6 +1928,162 @@ build_trait_object (tree type)
return build_stub_object (type);
  }
  
+/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If the

+   given is not invocable, returns error_mark_node.  */
+
+tree
+build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
+{
+  if (error_operand_p (fn_type) || error_operand_p (arg_types))
+return error_mark_node;
+
+  gcc_assert (TYPE_P (fn_type));
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* INVOKE is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+{
+  tree deref_fn_type = TREE_TYPE (fn_type);
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+  /* Dereference fn_type if it is a pointer to member.  */
+  if (is_ptrdatamem || is_ptrmemfunc)
+   fn_type = deref_fn_type;
+}
+  else
+{
+  is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+  is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+}
+
+  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
+{
+  if (complain & tf_error)
+   error ("pointer to data member type %qT can only be invoked with "
+  "one argument", fn_type);
+  return error_mark_node;
+}
+
+  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
+{
+  if (complain & tf_error)
+   error ("pointer to member function type %qT must be invoked with "
+  "at least one argument", fn_type);
+  return error_mark_node;
+}
+
+  /* Construct an expression of a pointer to member.  */
+  tree ptrmem_expr;
+  if (is_ptrdatamem || is_ptrmemfunc)
+{
+  tree datum_type = TREE_VEC_ELT (arg_types, 0);
+
+  /* datum must be a class type or a reference/pointer to a class type.  */
+  if (TYPE_REF_P (datum_type) || POINTER_TYPE_P (datum_type))
+{
+ if (!CLASS_TYPE_P (TREE_TYPE (datum_type)))
+   {
+ if (complain & tf_error)
+   error ("datum type %qT of a pointer to member must be a class"


I don't see the term "datum" anywhere in [func.require], let's refer to 
the "first argument" instead.



+  "type or a reference/pointer to a class type",
+  datum_type);
+ return error_mark_node;
+   }
+}
+  else if (!CLASS_TYPE_P (datum_type))
+   {
+ if (complain & tf_error)
+   error ("datum type %qT of a pointer to member must be a class"
+  "type or a reference/pointer to a class type",
+  datum_type);
+ return error_mark_node;
+   }
+
+  bool is_refwrap = false;
+  if (CLASS_TYPE_P (datum_type))
+   {
+ /* 1.2 & 1.5: Handle std::reference_wrapper.  */
+ tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
+ if (decl_in_std_namespace_p (datum_decl))
+   {
+ const_tree name = DECL_NAME (datum_decl);
+ if (name && (id_equal (name, "reference_wrapper")))
+   {
+ /* Retrieve T from std::reference_wrapper,
+i.e., decltype(datum.get()).  */
+ datum_type = TREE_VEC_ELT (TYPE_TI_ARGS (datum_type), 0);
+ is_refwrap = true;
+   }
+   }
+   }
+
+  tree datum_expr = build_trait_object (datum_type);
+  tree fn_expr = build_trait_object (fn_type);
+  ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain);


We should check same-or-base before trying this, not after.


+  if (error_operand_p (ptrmem_expr) && !is_refwrap)
+   {
+ tree ptrmem_class_type = TYPE_PTRMEM_CLASS_TYPE (fn_type);
+ const bool ptrmem_is_base_of_datum =
+   (NON_UNION_CLASS_TYPE_P (ptrmem_class_type)
+&& NON_UNION_CLASS_TYPE_P (datum_type)
+&& (same_type_ignoring_top_level_qualifiers_p (ptrmem_class_type,
+   datum_type)
+|| DERIVED_FROM_P (ptrmem_class_type, datum_type)));
+
+ if (!ptrmem_is_base_of_datum)
+   {
+ /* 1.3 & 1.6: Try to dereference datum_expr.  */
+ datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr,
+RO_UNARY_STAR, NULL_TREE,
+complain);
+

Re: [PATCH] c++/c-common: Fix convert_vector_to_array_for_subscript for qualified vector types [PR89224]

2024-04-30 Thread Jason Merrill

On 4/30/24 12:04, Andrew Pinski wrote:

On Tue, Apr 30, 2024 at 11:54 AM Jason Merrill  wrote:


On 2/20/24 19:06, Andrew Pinski wrote:

After r7-987-gf17a223de829cb, the access for the elements of a vector type 
would lose the qualifiers.
So if we had `constvector[0]`, the type of the element of the array would not 
have const on it.
This was due to a missing build_qualified_type for the inner type of the vector 
when building the array type.
We need to add back the call to build_qualified_type and now the access has the 
correct qualifiers. So the
overloads and even if it is a lvalue or rvalue is correctly done.

Note we correctly now reject the testcase gcc.dg/pr83415.c which was 
incorrectly accepted after r7-987-gf17a223de829cb.

Built and tested for aarch64-linux-gnu.

   PR c++/89224

gcc/c-family/ChangeLog:

   * c-common.cc (convert_vector_to_array_for_subscript): Call 
build_qualified_type
   for the inner type.

gcc/cp/ChangeLog:

   * constexpr.cc (cxx_eval_array_reference): Compare main variants
   for the vector/array types instead of the types directly.

gcc/testsuite/ChangeLog:

   * g++.dg/torture/vector-subaccess-1.C: New test.
   * gcc.dg/pr83415.c: Change warning to error.

Signed-off-by: Andrew Pinski 
---
   gcc/c-family/c-common.cc  |  7 +-
   gcc/cp/constexpr.cc   |  3 ++-
   .../g++.dg/torture/vector-subaccess-1.C   | 23 +++
   gcc/testsuite/gcc.dg/pr83415.c|  2 +-
   4 files changed, 32 insertions(+), 3 deletions(-)
   create mode 100644 gcc/testsuite/g++.dg/torture/vector-subaccess-1.C

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e15eff698df..884dd9043f9 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -8936,6 +8936,7 @@ convert_vector_to_array_for_subscript (location_t loc,
 if (gnu_vector_type_p (TREE_TYPE (*vecp)))
   {
 tree type = TREE_TYPE (*vecp);
+  tree newitype;

 ret = !lvalue_p (*vecp);

@@ -8950,8 +8951,12 @@ convert_vector_to_array_for_subscript (location_t loc,
for function parameters.  */
 c_common_mark_addressable_vec (*vecp);

+  /* Make sure qualifiers are copied from the vector type to the new 
element
+  of the array type.  */
+  newitype = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+
 *vecp = build1 (VIEW_CONVERT_EXPR,
-   build_array_type_nelts (TREE_TYPE (type),
+   build_array_type_nelts (newitype,
 TYPE_VECTOR_SUBPARTS (type)),
 *vecp);
   }
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fa346fe01c9..1fe91d16e8e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4421,7 +4421,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree 
t,
 if (!lval
 && TREE_CODE (ary) == VIEW_CONVERT_EXPR
 && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
-  && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0
+  && TYPE_MAIN_VARIANT (TREE_TYPE (t))
+   == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0)


Please add parens around the == expression so the formatting is stable.

ok, I will make that change.



With that change, OK for trunk and release branches.


For the GCC 14 branch, should I wait until after the release due to
RC1 going out today and I am not sure this counts as a show stopper
issue.


That's not my call ("all changes to the branch require a RM approval 
now") but I think it can wait for 14.2.


Jason



Re: [PATCH] c++/c-common: Fix convert_vector_to_array_for_subscript for qualified vector types [PR89224]

2024-04-30 Thread Jason Merrill

On 2/20/24 19:06, Andrew Pinski wrote:

After r7-987-gf17a223de829cb, the access for the elements of a vector type 
would lose the qualifiers.
So if we had `constvector[0]`, the type of the element of the array would not 
have const on it.
This was due to a missing build_qualified_type for the inner type of the vector 
when building the array type.
We need to add back the call to build_qualified_type and now the access has the 
correct qualifiers. So the
overloads and even if it is a lvalue or rvalue is correctly done.

Note we correctly now reject the testcase gcc.dg/pr83415.c which was 
incorrectly accepted after r7-987-gf17a223de829cb.

Built and tested for aarch64-linux-gnu.

PR c++/89224

gcc/c-family/ChangeLog:

* c-common.cc (convert_vector_to_array_for_subscript): Call 
build_qualified_type
for the inner type.

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_array_reference): Compare main variants
for the vector/array types instead of the types directly.

gcc/testsuite/ChangeLog:

* g++.dg/torture/vector-subaccess-1.C: New test.
* gcc.dg/pr83415.c: Change warning to error.

Signed-off-by: Andrew Pinski 
---
  gcc/c-family/c-common.cc  |  7 +-
  gcc/cp/constexpr.cc   |  3 ++-
  .../g++.dg/torture/vector-subaccess-1.C   | 23 +++
  gcc/testsuite/gcc.dg/pr83415.c|  2 +-
  4 files changed, 32 insertions(+), 3 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/torture/vector-subaccess-1.C

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e15eff698df..884dd9043f9 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -8936,6 +8936,7 @@ convert_vector_to_array_for_subscript (location_t loc,
if (gnu_vector_type_p (TREE_TYPE (*vecp)))
  {
tree type = TREE_TYPE (*vecp);
+  tree newitype;
  
ret = !lvalue_p (*vecp);
  
@@ -8950,8 +8951,12 @@ convert_vector_to_array_for_subscript (location_t loc,

 for function parameters.  */
c_common_mark_addressable_vec (*vecp);
  
+  /* Make sure qualifiers are copied from the vector type to the new element

+of the array type.  */
+  newitype = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+
*vecp = build1 (VIEW_CONVERT_EXPR,
- build_array_type_nelts (TREE_TYPE (type),
+ build_array_type_nelts (newitype,
  TYPE_VECTOR_SUBPARTS (type)),
  *vecp);
  }
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fa346fe01c9..1fe91d16e8e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4421,7 +4421,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree 
t,
if (!lval
&& TREE_CODE (ary) == VIEW_CONVERT_EXPR
&& VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
-  && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0
+  && TYPE_MAIN_VARIANT (TREE_TYPE (t))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0)


Please add parens around the == expression so the formatting is stable.

With that change, OK for trunk and release branches.

Jason



Re: [PATCH] c++/modules: Implement P2615 'Meaningful Exports' [PR107688]

2024-04-30 Thread Jason Merrill

On 3/4/24 06:18, Nathaniel Shead wrote:

Bootstrapped and regtested on x86_64-pc-linux-gnu. This should probably
wait for GCC 15 I suppose, but sending it in now in case there are any
comments.


OK for trunk.


-- >8 --

This clarifies which kinds of declarations may and may not be exported
in various contexts. The patch additionally fixes up some small issues
that were clarified by the paper.

Most of the changes are with regards to export-declarations, which are
applied for all standards modes that we support '-fmodules-ts' for.
However there are also a couple of changes made to linkage specifiers
('extern "C"'); I've applied these as since C++20, to line up with when
modules were actually introduced.

PR c++/107688

gcc/cp/ChangeLog:

* name-lookup.cc (push_namespace): Error when exporting
namespace with internal linkage.
* parser.h (struct cp_parser): Add new flag
'in_unbraced_export_declaration_p'.
* parser.cc (cp_debug_parser): Print the new flag.
(cp_parser_new): Initialise the new flag.
(cp_parser_module_export): Set the new flag.
(cp_parser_class_specifier): Clear and restore the new flag.
(cp_parser_import_declaration): Imports can now appear directly
in a linkage specification.
(cp_parser_declaration): Categorise declarations as "name" or
"special"; error on the later in contexts where the former is
required.
(cp_parser_class_head): Error when exporting a partial
specialisation.

gcc/testsuite/ChangeLog:

* g++.dg/modules/contracts-1_a.C: Avoid now-illegal syntax.
* g++.dg/modules/contracts-2_a.C: Likewise.
* g++.dg/modules/contracts-3_a.C: Likewise.
* g++.dg/modules/contracts-4_a.C: Likewise.
* g++.dg/modules/lang-1_c.C: Clarify now-legal syntax.
* g++.dg/template/crash71.C: Update error messages.
* g++.dg/cpp2a/linkage-spec1.C: New test.
* g++.dg/modules/export-3.C: New test.
* g++.dg/modules/export-4_a.C: New test.
* g++.dg/modules/export-4_b.C: New test.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/name-lookup.cc|  10 +-
  gcc/cp/parser.cc | 105 +++
  gcc/cp/parser.h  |   6 +-
  gcc/testsuite/g++.dg/cpp2a/linkage-spec1.C   |  22 
  gcc/testsuite/g++.dg/modules/contracts-1_a.C |   2 +-
  gcc/testsuite/g++.dg/modules/contracts-2_a.C |   2 +-
  gcc/testsuite/g++.dg/modules/contracts-3_a.C |   2 +-
  gcc/testsuite/g++.dg/modules/contracts-4_a.C |   2 +-
  gcc/testsuite/g++.dg/modules/export-3.C  |  30 ++
  gcc/testsuite/g++.dg/modules/export-4_a.C|  23 
  gcc/testsuite/g++.dg/modules/export-4_b.C|  13 +++
  gcc/testsuite/g++.dg/modules/lang-1_c.C  |   2 +-
  gcc/testsuite/g++.dg/template/crash71.C  |   4 +-
  13 files changed, 192 insertions(+), 31 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/linkage-spec1.C
  create mode 100644 gcc/testsuite/g++.dg/modules/export-3.C
  create mode 100644 gcc/testsuite/g++.dg/modules/export-4_a.C
  create mode 100644 gcc/testsuite/g++.dg/modules/export-4_b.C

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 6444db3f0eb..743102d8393 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -9053,8 +9053,14 @@ push_namespace (tree name, bool make_inline)
  {
/* A public namespace is exported only if explicitly marked, or
 it contains exported entities.  */
-  if (TREE_PUBLIC (ns) && module_exporting_p ())
-   DECL_MODULE_EXPORT_P (ns) = true;
+  if (module_exporting_p ())
+   {
+ if (TREE_PUBLIC (ns))
+   DECL_MODULE_EXPORT_P (ns) = true;
+ else if (!header_module_p ())
+   error_at (input_location,
+ "exporting namespace with internal linkage");
+   }
if (module_purview_p ())
DECL_MODULE_PURVIEW_P (ns) = true;
  
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc

index a310b9e8c07..448392e1bd9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -560,6 +560,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
   & THIS_FORBIDDEN));
cp_debug_print_flag (file, "In unbraced linkage specification",
  parser->in_unbraced_linkage_specification_p);
+  cp_debug_print_flag (file, "In unbraced export declaration",
+ parser->in_unbraced_export_declaration_p);
cp_debug_print_flag (file, "Parsing a declarator",
  parser->in_declarator_p);
cp_debug_print_flag (file, "In template argument list",
@@ -4425,6 +4427,9 @@ cp_parser_new (cp_lexer *lexer)
/* We are not processing an `extern "C"' declaration.  */
parser->in_unbraced_linkage_specification_p = false;
  
+  /* We aren't parsing an export-declaration.  */

+  parser->in_unbraced_export_declaration_p = false;
+
   

Re: [PATCH 2/3] c++/modules: Propagate using decls from partitions

2024-04-30 Thread Jason Merrill

On 4/30/24 00:59, Nathaniel Shead wrote:

On Sun, Apr 14, 2024 at 01:40:18AM +1000, Nathaniel Shead wrote:

On Fri, Apr 12, 2024 at 01:50:47PM -0400, Jason Merrill wrote:

On 4/11/24 20:40, Nathaniel Shead wrote:

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

-- >8 --

The modules code currently neglects to set OVL_USING_P on the dependency
created for a using-decl, which causes it not to remember that the
OVL_EXPORT_P flag had been set on it when emitted from the primary
interface unit. This patch ensures that it occurs.

gcc/cp/ChangeLog:

* module.cc (depset::hash::add_binding_entity): Propagate
OVL_USING_P for using-declarations.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-15_a.C: New test.
* g++.dg/modules/using-15_b.C: New test.
* g++.dg/modules/using-15_c.C: New test.

Signed-off-by: Nathaniel Shead 
---
   gcc/cp/module.cc  |  4 
   gcc/testsuite/g++.dg/modules/using-15_a.C | 13 +
   gcc/testsuite/g++.dg/modules/using-15_b.C |  5 +
   gcc/testsuite/g++.dg/modules/using-15_c.C |  7 +++
   4 files changed, 29 insertions(+)
   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_a.C
   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_b.C
   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_c.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 9d054c4c792..527c9046c67 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12915,10 +12915,12 @@ depset::hash::add_binding_entity (tree decl, 
WMB_Flags flags, void *data_)
/* Ignore NTTP objects.  */
return false;
+  bool unscoped_enum_const_p = false;
 if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns)
{
  /* A using that lost its wrapper or an unscoped enum
 constant.  */
+ unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL);


How does this interact with C++20 using enum?


Looks like it ignores those (so they still suffer from this error).  But
in general we don't handle usings of non-functions correctly anyway yet
(for the reasons I described in the cover letter); I just added this for
now to prevent regressing some test-cases caused by importing enum
consts wrapped in an OVERLOAD.

Otherwise happy to defer this patch until GCC 15 when I can look at
exploring what needs to be done to handle non-function using-decls
correctly, but I'll need to work out a new testcase for the followup
patch in this series (or just defer that one too, I suppose).


Ping.  Or should I just scrap this patch for now, find a new testcase
for the followup patch, and submit it again once we have a general
solution for using-decls of non-functions?


Please add a FIXME about using enum here and a using enum testcase to 
the appropriate PR; OK for trunk and 14.2 with that change.


Jason



Re: [PATCH] c++: Implement C++26 P0609R3 - Attributes for Structured Bindings [PR114456]

2024-04-29 Thread Jason Merrill

On 4/29/24 00:11, Jakub Jelinek wrote:

Hi!

The following patch implements the P0609R3 paper; we build the
VAR_DECLs for the structured binding identifiers early, so all we need
IMHO is just to parse the attributed identifier list and pass the attributes
to the VAR_DECL creation.

The paper mentions maybe_unused and gnu::nonstring attributes as examples
where they can be useful.  Not sure about either of them.
For maybe_unused, the thing is that both GCC and clang already don't
diagnose maybe unused for the structured binding identifiers, because it
would be a false positive too often; and there is no easy way to find out
if a structured binding has been written with the P0609R3 paper in mind or
not (maybe we could turn it on if in the structured binding is any
attribute, even if just [[]] and record that as a flag on the whole
underlying decl, so that we'd diagnose
   auto [a, b, c[[]]] = d;
   // use a, c but not b
but not
   auto [e, f, g] = d;
   // use a, c but not b
).  For gnu::nonstring, the issue is that we currently don't allow the
attribute on references to char * or references to char[], just on
char */char[].  I've filed a PR for that.

The first testcase in the patch tests it on [[]] and [[maybe_unused]],
just whether it is parsed properly, second on gnu::deprecated, which
works.  Haven't used deprecated attribute because the paper said that
attribute is for further investigation.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


OK.


2024-04-29  Jakub Jelinek  

PR c++/114456
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine
__cpp_structured_bindings for C++26 to 202403L rather than
201606L.
gcc/cp/
* parser.cc (cp_parser_decomposition_declaration): Implement C++26
P0609R3 - Attributes for Structured Bindings.  Parse attributed
identifier lists for structured binding declarations, pass the
attributes to start_decl.
gcc/testsuite/
* g++.dg/cpp26/decomp1.C: New test.
* g++.dg/cpp26/decomp2.C: New test.
* g++.dg/cpp26/feat-cxx26.C (__cpp_structured_bindings): Expect
202403 rather than 201606.

--- gcc/cp/parser.cc.jj 2024-04-26 11:42:24.653016208 +0200
+++ gcc/cp/parser.cc2024-04-26 13:59:17.791482874 +0200
@@ -16075,13 +16075,37 @@ cp_parser_decomposition_declaration (cp_
  
/* Parse the identifier-list.  */

auto_vec v;
+  bool attr_diagnosed = false;
+  int first_attr = -1;
+  unsigned int cnt = 0;
if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
  while (true)
{
cp_expr e = cp_parser_identifier (parser);
if (e.get_value () == error_mark_node)
  break;
+   tree attr = NULL_TREE;
+   if (cp_next_tokens_can_be_std_attribute_p (parser))
+ {
+   if (cxx_dialect >= cxx17 && cxx_dialect < cxx26 && !attr_diagnosed)
+ {
+   pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+OPT_Wc__26_extensions,
+"structured bindings with attributed identifiers "
+"only available with %<-std=c++2c%> or "
+"%<-std=gnu++2c%>");
+   attr_diagnosed = true;
+ }
+   attr = cp_parser_std_attribute_spec_seq (parser);
+   if (attr == error_mark_node)
+ attr = NULL_TREE;
+   if (attr && first_attr == -1)
+ first_attr = v.length ();
+ }
v.safe_push (e);
+   ++cnt;
+   if (first_attr != -1)
+ v.safe_push (attr);
if (!cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
  break;
cp_lexer_consume_token (parser->lexer);
@@ -16139,8 +16163,11 @@ cp_parser_decomposition_declaration (cp_
  declarator->id_loc = e.get_location ();
}
tree elt_pushed_scope;
+  tree attr = NULL_TREE;
+  if (first_attr != -1 && i >= (unsigned) first_attr)
+   attr = v[++i].get_value ();
tree decl2 = start_decl (declarator, _specs, SD_DECOMPOSITION,
-  NULL_TREE, NULL_TREE, _pushed_scope);
+  NULL_TREE, attr, _pushed_scope);
if (decl2 == error_mark_node)
decl = error_mark_node;
else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev)
@@ -16183,7 +16210,7 @@ cp_parser_decomposition_declaration (cp_
  
if (decl != error_mark_node)

{
- cp_decomp decomp = { prev, v.length () };
+ cp_decomp decomp = { prev, cnt };
  cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
  (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT),
  );
@@ -16193,7 +16220,7 @@ cp_parser_decomposition_declaration (cp_
else if (decl != error_mark_node)
  {
*maybe_range_for_decl = prev;
-  cp_decomp decomp = { prev, v.length () };
+  cp_decomp decomp = { prev, cnt };
/* 

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

2024-04-29 Thread Jason Merrill

On 4/29/24 02:34, Nathaniel Shead wrote:

On Fri, Apr 26, 2024 at 09:16:40PM -0400, Jason Merrill wrote:

On 4/19/24 09:29, Nathaniel Shead wrote:

On Fri, Apr 19, 2024 at 12:14:06PM +1000, Nathaniel Shead wrote:

On Wed, Apr 17, 2024 at 02:02:21PM -0400, Patrick Palka wrote:

On Mon, 15 Apr 2024, Nathaniel Shead wrote:


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


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


Yes, it should either just be a 0 byte or an additional backref
somewhere, which will likely also be small. On my system it increases
the size by 0.26%, from 31186800 bytes to 31268672.

But I've just found that this patch has a bug anyway, in that it doesn't
correctly dedup if the friend types are instantiated in two separate
modules that are then both imported.  I'll see what I need to do to fix
this which may influence what we need to stream here.



Here's an updated version of the patch that fixes this. Also changed to
only stream when 'inner' is either TYPE_DECL or FUNCTION_DECL, which
cuts the size of  down a bit to 31246992 (0.19% growth).

Another alternative would be to add another boolean flag at the top of
'decl_value' and branch on that; that would make use of the bitpacking
logic and probably cut down on the size further.  (I haven't measured
this yet though.)

Bootstrapped and regtested (so far just dg.exp and modules.exp) on
x86_64-pc-linux-gnu, OK for trunk if full regtest succeeds?

-- >8 --

This patch fixes a number of issues with the handling of temploid friend
declarations.

The primary issue is that instantiations of friend declarations should
attach the declaration to the same module as the befriending class, by
[module.unit] p7.1 and [temp.friend] p2; this could be a different
module from the current TU, and so needs special handling.


This is only an issue for DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P, right?


It's true for any friend instantiations, including e.g. friend
functions, not just template class friends.



Hmm, CWG2588 should probably touch [module.unit]/7.1 as well as
[basic.link].


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


Tricksy.


This doesn't appear necessary for functions due to the existing name
lookup handling already finding these hidden declarations.

PR c++/105320
PR c++/114275

gcc/cp/ChangeLog:

* cp-tree.h (propagate_defining_module): Declare.
(lookup_imported_hidden_friend): Declare.
* decl.cc (duplicate_decls): Also check if hidden declarations
can be redeclared in this module.
* module.cc (imported_temploid_friends): New map.
(init_modules): Initialize it.
(trees_out::decl_value): Write it; don't consider imported
temploid friends as attached to this module.
(trees_in::decl_value): Read it.
(depset::hash::add_specializations): Don't treat instantiations
of a friend type as a specialisation.
(get_originating_module_decl): Follow the owning decl for an
imported temploid friend.
(propagate_defining_module): New function.
* name-lookup.cc (lookup_imported_hidden_friend): New function.
* pt.cc (tsubst_friend_function): Propagate defining module for
new friend functions.
(tsubst_friend_class): Lookup imported hidden friends. Check
for valid redeclaration. Propagate defining module for new
friend classes.

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index aa66da4829d..56752cf6872 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2276,30 +2276,34 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
 if (modules_p ()
 && TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL
-  && TREE_CODE (olddecl) != NAMESPACE_DECL
-  && !hiding)
+  && TREE_CODE (olddecl) != NAMESPACE_DECL)
   {
 if (!module_may_redeclare (olddecl, newdecl))
return error_mark_node;
-  tree not_tmpl = STRIP_TEMPLATE (olddecl);
-  if (DECL_LANG_SPECIFIC (not_tmpl)
- && DECL_MODULE_ATTACH_P (not_tmpl)
- /* Typedefs are not entities and so are OK to be redeclared
-   

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

2024-04-29 Thread Jason Merrill

On 4/29/24 06:50, Patrick Palka wrote:

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


OK for both.


-- >8 --

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

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

PR c++/114889

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7e654305f0a..3b2ba40c92b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12518,6 +12518,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
  
  	  if (CLASS_TYPE_P (f))

{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}




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

2024-04-29 Thread Jason Merrill

On 4/29/24 07:52, Marek Polacek wrote:

On Mon, Apr 29, 2024 at 10:28:19AM -0400, Patrick Palka wrote:

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


LGTM.


Yes, OK.


-- >8 --

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

PR c++/114888

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

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



Marek





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

2024-04-26 Thread Jason Merrill

On 4/19/24 09:29, Nathaniel Shead wrote:

On Fri, Apr 19, 2024 at 12:14:06PM +1000, Nathaniel Shead wrote:

On Wed, Apr 17, 2024 at 02:02:21PM -0400, Patrick Palka wrote:

On Mon, 15 Apr 2024, Nathaniel Shead wrote:


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


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


Yes, it should either just be a 0 byte or an additional backref
somewhere, which will likely also be small. On my system it increases
the size by 0.26%, from 31186800 bytes to 31268672.

But I've just found that this patch has a bug anyway, in that it doesn't
correctly dedup if the friend types are instantiated in two separate
modules that are then both imported.  I'll see what I need to do to fix
this which may influence what we need to stream here.



Here's an updated version of the patch that fixes this. Also changed to
only stream when 'inner' is either TYPE_DECL or FUNCTION_DECL, which
cuts the size of  down a bit to 31246992 (0.19% growth).

Another alternative would be to add another boolean flag at the top of
'decl_value' and branch on that; that would make use of the bitpacking
logic and probably cut down on the size further.  (I haven't measured
this yet though.)

Bootstrapped and regtested (so far just dg.exp and modules.exp) on
x86_64-pc-linux-gnu, OK for trunk if full regtest succeeds?

-- >8 --

This patch fixes a number of issues with the handling of temploid friend
declarations.

The primary issue is that instantiations of friend declarations should
attach the declaration to the same module as the befriending class, by
[module.unit] p7.1 and [temp.friend] p2; this could be a different
module from the current TU, and so needs special handling.


This is only an issue for DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P, right?

Hmm, CWG2588 should probably touch [module.unit]/7.1 as well as 
[basic.link].



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


Tricksy.


This doesn't appear necessary for functions due to the existing name
lookup handling already finding these hidden declarations.

PR c++/105320
PR c++/114275

gcc/cp/ChangeLog:

* cp-tree.h (propagate_defining_module): Declare.
(lookup_imported_hidden_friend): Declare.
* decl.cc (duplicate_decls): Also check if hidden declarations
can be redeclared in this module.
* module.cc (imported_temploid_friends): New map.
(init_modules): Initialize it.
(trees_out::decl_value): Write it; don't consider imported
temploid friends as attached to this module.
(trees_in::decl_value): Read it.
(depset::hash::add_specializations): Don't treat instantiations
of a friend type as a specialisation.
(get_originating_module_decl): Follow the owning decl for an
imported temploid friend.
(propagate_defining_module): New function.
* name-lookup.cc (lookup_imported_hidden_friend): New function.
* pt.cc (tsubst_friend_function): Propagate defining module for
new friend functions.
(tsubst_friend_class): Lookup imported hidden friends. Check
for valid redeclaration. Propagate defining module for new
friend classes.

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index aa66da4829d..56752cf6872 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2276,30 +2276,34 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
  
if (modules_p ()

&& TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL
-  && TREE_CODE (olddecl) != NAMESPACE_DECL
-  && !hiding)
+  && TREE_CODE (olddecl) != NAMESPACE_DECL)
  {
if (!module_may_redeclare (olddecl, newdecl))
return error_mark_node;
  
-  tree not_tmpl = STRIP_TEMPLATE (olddecl);

-  if (DECL_LANG_SPECIFIC (not_tmpl)
- && DECL_MODULE_ATTACH_P (not_tmpl)
- /* Typedefs are not entities and so are OK to be redeclared
-as exported: see [module.interface]/p6.  */
- && TREE_CODE (olddecl) != TYPE_DECL)
+  if (!hiding)
{
- if (DECL_MODULE_EXPORT_P (STRIP_TEMPLATE (newdecl))
- && !DECL_MODULE_EXPORT_P (not_tmpl))
+ /* Hidden friend 

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

2024-04-25 Thread Jason Merrill

On 4/19/24 09:18, Nathaniel Shead wrote:

On Mon, Apr 15, 2024 at 02:49:35PM +1000, Nathaniel Shead wrote:

I took another look at this patch and have split it into two, one (this
one) to standardise the error messages used and prepare
'module_may_redeclare' for use with temploid friends, and another
followup patch to actually handle them correctly.

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

-- >8 --

Currently different places calling 'module_may_redeclare' all emit very
similar but slightly different error messages, and handle different
kinds of declarations differently.  This patch makes the function
perform its own error messages so that they're all in one place, and
prepares it for use with temploid friends (PR c++/114275).

gcc/cp/ChangeLog:

* cp-tree.h (module_may_redeclare): Add default parameter.
* decl.cc (duplicate_decls): Don't emit errors for failed
module_may_redeclare.
(xref_tag): Likewise.
(start_enum): Likewise.
* semantics.cc (begin_class_definition): Likewise.
* module.cc (module_may_redeclare): Clean up logic. Emit error
messages on failure.

gcc/testsuite/ChangeLog:

* g++.dg/modules/enum-12.C: Update error message.
* g++.dg/modules/friend-5_b.C: Likewise.
* g++.dg/modules/shadow-1_b.C: Likewise.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/cp-tree.h  |   2 +-
  gcc/cp/decl.cc|  28 +
  gcc/cp/module.cc  | 120 ++
  gcc/cp/semantics.cc   |   6 +-
  gcc/testsuite/g++.dg/modules/enum-12.C|   2 +-
  gcc/testsuite/g++.dg/modules/friend-5_b.C |   2 +-
  gcc/testsuite/g++.dg/modules/shadow-1_b.C |   5 +-
  7 files changed, 89 insertions(+), 76 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1dbb577a38d..faa7a0052a5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7401,7 +7401,7 @@ inline bool module_exporting_p ()
  
  extern module_state *get_module (tree name, module_state *parent = NULL,

 bool partition = false);
-extern bool module_may_redeclare (tree decl);
+extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL);
  
  extern bool module_global_init_needed ();

  extern bool module_determine_import_inits ();
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 65ab64885ff..aa66da4829d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
&& TREE_CODE (olddecl) != NAMESPACE_DECL
&& !hiding)
  {
-  if (!module_may_redeclare (olddecl))
-   {
- if (DECL_ARTIFICIAL (olddecl))
-   error ("declaration %qD conflicts with builtin", newdecl);
- else
-   {
- error ("declaration %qD conflicts with import", newdecl);
- inform (olddecl_loc, "import declared %q#D here", olddecl);
-   }
-
- return error_mark_node;
-   }
+  if (!module_may_redeclare (olddecl, newdecl))
+   return error_mark_node;
  
tree not_tmpl = STRIP_TEMPLATE (olddecl);

if (DECL_LANG_SPECIFIC (not_tmpl)
@@ -16620,12 +16610,7 @@ xref_tag (enum tag_types tag_code, tree name,
{
  tree decl = TYPE_NAME (t);
  if (!module_may_redeclare (decl))
-   {
- auto_diagnostic_group d;
- error ("cannot declare %qD in a different module", decl);
- inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
- return error_mark_node;
-   }
+   return error_mark_node;
  
  	  tree not_tmpl = STRIP_TEMPLATE (decl);

  if (DECL_LANG_SPECIFIC (not_tmpl)
@@ -16973,12 +16958,7 @@ start_enum (tree name, tree enumtype, tree 
underlying_type,
{
  tree decl = TYPE_NAME (enumtype);
  if (!module_may_redeclare (decl))
-   {
- auto_diagnostic_group d;
- error ("cannot declare %qD in different module", decl);
- inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
- enumtype = error_mark_node;
-   }
+   enumtype = error_mark_node;
  else
set_instantiating_module (decl);
}
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 001430a4a8f..e2d2910ae48 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -18992,11 +18992,15 @@ get_importing_module (tree decl, bool flexible)
return module->mod;
  }
  
-/* Is it permissible to redeclare DECL.  */

+/* Is it permissible to redeclare OLDDECL with NEWDECL.
+
+   If NEWDECL is NULL, assumes that OLDDECL will be redeclared using
+   the current scope's module and attachment.  */
  
  bool

-module_may_redeclare (tree decl)
+module_may_redeclare (tree olddecl, tree newdecl)
  {
+  tree decl = olddecl;
for (;;)
  {
tree ctx = 

Re: [PATCH] c++, v2: Fix constexpr evaluation of parameters passed by invisible reference [PR111284]

2024-04-25 Thread Jason Merrill

On 4/23/24 08:52, Jakub Jelinek wrote:

On Mon, Apr 15, 2024 at 02:19:36PM +0200, Jakub Jelinek wrote:

They weren't the same, one was trying to evaluate the convert_from_reference
with vc_glvalue, the other evaluates it without that and with vc_prvalue.
Now, I guess the
+ /* Undo convert_for_arg_passing work here.  */
+ if (TYPE_REF_P (TREE_TYPE (x))
+ && !same_type_p (type, TREE_TYPE (TREE_TYPE (x
+   x = cp_fold_convert (build_reference_type (type), x);
part could be thrown away, given the other !same_type_p check (that one is
needed because adjust_temp_type can't deal with that), at least
when I remove that
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ 
RUNTESTFLAGS="dg.exp='constexpr-dtor* pr114426.C constexpr-111284.C 
constexpr-lifetime7.C'"
still passes.


I've now tested that version and it passed bootstrap/regtest on x86_64-linux
and i686-linux.  But as I said earlier, trying to tweak the patch further
doesn't work on the constexpr-dtor{5,6}.C tests.


OK.


2024-04-23  Jakub Jelinek  

PR c++/111284
* constexpr.cc (cxx_bind_parameters_in_call): For PARM_DECLs with
TREE_ADDRESSABLE types use vc_glvalue rather than vc_prvalue for
cxx_eval_constant_expression and if it doesn't have the same
type as it should, cast the reference type to reference to type
before convert_from_reference and instead of adjust_temp_type
take address of the arg, cast to reference to type and then
convert_from_reference.
(cxx_eval_constant_expression) : For lval case
on parameters with TREE_ADDRESSABLE types lookup result in
ctx->globals if possible.  Otherwise if lookup in ctx->globals
was successful for parameter with TREE_ADDRESSABLE type,
recurse with vc_prvalue on the returned value.

* g++.dg/cpp1z/constexpr-111284.C: New test.
* g++.dg/cpp1y/constexpr-lifetime7.C: Expect one error on a different
line.

--- gcc/cp/constexpr.cc.jj  2024-02-13 10:29:57.979155641 +0100
+++ gcc/cp/constexpr.cc 2024-03-07 19:35:01.032412221 +0100
@@ -1877,13 +1877,18 @@ cxx_bind_parameters_in_call (const const
  x = build_address (x);
}
if (TREE_ADDRESSABLE (type))
-   /* Undo convert_for_arg_passing work here.  */
-   x = convert_from_reference (x);
-  /* Normally we would strip a TARGET_EXPR in an initialization context
-such as this, but here we do the elision differently: we keep the
-TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm.  */
-  arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
- non_constant_p, overflow_p);
+   {
+ /* Undo convert_for_arg_passing work here.  */
+ x = convert_from_reference (x);
+ arg = cxx_eval_constant_expression (ctx, x, vc_glvalue,
+ non_constant_p, overflow_p);
+   }
+  else
+   /* Normally we would strip a TARGET_EXPR in an initialization context
+  such as this, but here we do the elision differently: we keep the
+  TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm.  */
+   arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
+   non_constant_p, overflow_p);
/* Check we aren't dereferencing a null pointer when calling a 
non-static
 member function, which is undefined behaviour.  */
if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun)
@@ -1909,7 +1914,16 @@ cxx_bind_parameters_in_call (const const
{
  /* Make sure the binding has the same type as the parm.  But
 only for constant args.  */
- if (!TYPE_REF_P (type))
+ if (TREE_ADDRESSABLE (type))
+   {
+ if (!same_type_p (type, TREE_TYPE (arg)))
+   {
+ arg = build_fold_addr_expr (arg);
+ arg = cp_fold_convert (build_reference_type (type), arg);
+ arg = convert_from_reference (arg);
+   }
+   }
+ else if (!TYPE_REF_P (type))
arg = adjust_temp_type (type, arg);
  if (!TREE_CONSTANT (arg))
*non_constant_args = true;
@@ -7499,9 +7513,19 @@ cxx_eval_constant_expression (const cons
  
  case PARM_DECL:

if (lval && !TYPE_REF_P (TREE_TYPE (t)))
-   /* glvalue use.  */;
+   {
+ /* glvalue use.  */
+ if (TREE_ADDRESSABLE (TREE_TYPE (t)))
+   if (tree v = ctx->global->get_value (t))
+ r = v;
+   }
else if (tree v = ctx->global->get_value (t))
-   r = v;
+   {
+ r = v;
+ if (TREE_ADDRESSABLE (TREE_TYPE (t)))
+   r = cxx_eval_constant_expression (ctx, r, vc_prvalue,
+ non_constant_p, overflow_p);
+   }
else if (lval)
/* Defer in case this is only used for its type.  

Re: [PATCH] c++, v4: Retry the aliasing of base/complete cdtor optimization at import_export_decl time [PR113208]

2024-04-25 Thread Jason Merrill

On 4/25/24 07:22, Jakub Jelinek wrote:

On Thu, Apr 25, 2024 at 02:02:32PM +0200, Jakub Jelinek wrote:

I've tried the following patch, but unfortunately that lead to large
number of regressions:
+FAIL: g++.dg/cpp0x/initlist25.C  -std=c++17 (test for excess errors)


So the reduced testcase for this is
template  struct A {
   T a1;
   U a2;
   template 
   constexpr A(V &, W &) : a1(x), a2(y) {}
};
template  struct B;
namespace std {
template  struct initializer_list {
   int *_M_array;
   decltype (sizeof 0) _M_len;
};
}
template  struct C {
   void foo (std::initializer_list>);
};
template  struct D;
template , typename = B>
struct E { E (const char *); ~E (); };
int
main ()
{
   C, E> m;
   m.foo ({{"t", "t"}, {"y", "y"}});
}
Without the patch I've just posted or even with the earlier version
of the patch the
_ZN1AIK1EIc1DIcE1BIcEES5_EC[12]IRA2_KcSB_Lb1EEEOT_OT0_
ctors were emitted, but with this patch they are unresolved externals.

The reason is that the code actually uses (calls) the
_ZN1AIK1EIc1DIcE1BIcEES5_EC1IRA2_KcSB_Lb1EEEOT_OT0_
__ct_comp constructor, that one has TREE_USED, while the
_ZN1AIK1EIc1DIcE1BIcEES5_EC2IRA2_KcSB_Lb1EEEOT_OT0_
__ct_base constructor is not TREE_USED.

But the c_parse_final_cleanups loop over
FOR_EACH_VEC_SAFE_ELT (deferred_fns, i, decl)
will ignore the TREE_USED __ct_comp because it is an alias
and so has !DECL_SAVED_TREE:
5273  if (!DECL_SAVED_TREE (decl))
5274continue;


Hmm, maybe maybe_clone_body shouldn't clear DECL_SAVED_TREE for aliases, 
but rather set it to some stub like void_node?


Though with all these changes, it's probably better to go with your 
first patch for GCC 14 and delay this approach to 15.  Your v1 patch is 
OK for 14.


Jason



Re: [PATCH] c++, v3: Retry the aliasing of base/complete cdtor optimization at import_export_decl time [PR113208]

2024-04-24 Thread Jason Merrill

On 4/24/24 15:47, Jakub Jelinek wrote:

On Wed, Apr 24, 2024 at 06:39:33PM -0400, Jason Merrill wrote:

--- gcc/cp/decl2.cc.jj  2024-04-23 14:49:41.933186265 +0200
+++ gcc/cp/decl2.cc 2024-04-24 15:17:09.043625729 +0200
@@ -3314,7 +3314,16 @@ tentative_decl_linkage (tree decl)
 to mark the functions at this point.  */
  if (DECL_DECLARED_INLINE_P (decl)
  && (!DECL_IMPLICIT_INSTANTIATION (decl)
- || DECL_DEFAULTED_FN (decl)))
+ || DECL_DEFAULTED_FN (decl)
+ /* For implicit instantiations of cdtors,
+if import_export_decl would use comdat linkage,
+make sure to use it right away, so that maybe_clone_body
+can use aliases.  See PR113208.  */
+ || (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)
+ && (flag_implicit_templates
+ || flag_implicit_inline_templates)
+ && flag_weak
+ && TARGET_SUPPORTS_ALIASES)))


It seems wrong to set DECL_INTERFACE_KNOWN for cdtors that might get an
explicit instantiation later, and likewise for comdat_linkage when
!flag_weak; instead of adding this condition to the if, how about adding an
else like


   else if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl))
 /* For implicit instantiations of cdtors,
if import_export_decl would use comdat linkage,
make sure to use it right away, so that maybe_clone_body
can use aliases.  See PR113208.  */
 maybe_make_one_only (decl);


?


Then can_alias_cdtor would return false, because it ends with:
   /* Don't use aliases for weak/linkonce definitions unless we can put both
  symbols in the same COMDAT group.  */
   return (DECL_INTERFACE_KNOWN (fn)
   && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn))
   && (!DECL_ONE_ONLY (fn)
   || (HAVE_COMDAT_GROUP && DECL_WEAK (fn;
Should we change that DECL_INTERFACE_KNOWN (fn) in there to
(DECL_INTERFACE_KNOWN (fn) || something) then and what that
something should be?  HAVE_COMDAT_GROUP && DECL_ONE_ONLY (fn)?


Yes, I think reorganize to

((DECL_INTERFACE_KNOWN (fn) && !DECL_WEAK (fn) && !DECL_ONE_ONLY (fn))
 || (HAVE_COMDAT_GROUP && DECL_ONE_ONLY (fn))

Jason



Re: [PATCH] c++, v3: Retry the aliasing of base/complete cdtor optimization at import_export_decl time [PR113208]

2024-04-24 Thread Jason Merrill

On 4/24/24 09:16, Jakub Jelinek wrote:

On Wed, Apr 24, 2024 at 10:16:05AM +0100, Jonathan Wakely wrote:

That fixes the testcases too, but seems to regress
+FAIL: libstdc++-abi/abi_check



There are explicit instantiation definitions that should instantiate
those types:

src/c++17/fs_dir.cc:template class std::__shared_ptr;
src/c++17/fs_dir.cc:template class
std::__shared_ptr;
src/c++17/fs_path.cc:template class std::__shared_ptr;

So the missing symbols should be present in cow-fs_dir.o and cow-fs_path.o


So this boils down to (cvise reduced):
namespace __gnu_cxx { enum _Lock_policy { _S_single, _S_mutex, _S_atomic } 
const __default_lock_policy = _S_atomic; }
namespace std {
using __gnu_cxx::__default_lock_policy;
using __gnu_cxx::_Lock_policy;
template  struct __shared_ptr { 
constexpr __shared_ptr() {} };
namespace filesystem {
struct _Dir;
struct directory_iterator { __shared_ptr<_Dir> _M_dir; };
void end() { directory_iterator(); } }
extern template class __shared_ptr;
}
namespace fs = std::filesystem;
template class std::__shared_ptr;
at -O2, previously it used to emit
_ZNSt12__shared_ptrINSt10filesystem4_DirELN9__gnu_cxx12_Lock_policyE2EEC2Ev
_ZNSt12__shared_ptrINSt10filesystem4_DirELN9__gnu_cxx12_Lock_policyE1EEC2Ev
but now no longer does with the yesterday posted PR113208 patch.

The following updated patch fixes that by calling note_vague_linkage_fn for
the cdtor clones from maybe_clone_body if the flags suggest that the
maybe-in-charge cdtor had tentative_decl_linkage -> note_vague_linkage_fn
called too.  And then I've noticed that in some cases the updated comdat
group set by maybe_clone_body (*C5* or *D5*) was then overwritten again by
maybe_make_one_only.  So the patch tweaks cxx_comdat_group, so that when
some comdat group has been chosen already it doesn't try to use some
different one.

Bootstrapped/regtested on x86_64-linux and i686-linux, this one doesn't
regress anything unlike the earlier patch.

2024-04-24  Jakub Jelinek  

PR lto/113208
* decl2.cc (tentative_decl_linkage): Use comdat_linkage also
for implicit instantiations of maybe in charge ctors/dtors
if -fimplicit-templates or -fimplicit-inline-templates and
-fweak and target supports aliases.
* optimize.cc (maybe_clone_body): Call note_vague_linkage_fn
on clone if fn has DECL_INTERFACE_KNOWN, DECL_NOT_REALLY_EXTERN
and DECL_DEFER_OUTPUT flags set.
* decl.cc (cxx_comdat_group): For DECL_CLONED_FUNCTION_P
functions if SUPPORTS_ONE_ONLY return DECL_COMDAT_GROUP if already
set.

* g++.dg/abi/comdat2.C: New test.
* g++.dg/abi/comdat3.C: New test.
* g++.dg/lto/pr113208_0.C: New test.
* g++.dg/lto/pr113208_1.C: New file.
* g++.dg/lto/pr113208.h: New file.

--- gcc/cp/decl2.cc.jj  2024-04-23 14:49:41.933186265 +0200
+++ gcc/cp/decl2.cc 2024-04-24 15:17:09.043625729 +0200
@@ -3314,7 +3314,16 @@ tentative_decl_linkage (tree decl)
 to mark the functions at this point.  */
  if (DECL_DECLARED_INLINE_P (decl)
  && (!DECL_IMPLICIT_INSTANTIATION (decl)
- || DECL_DEFAULTED_FN (decl)))
+ || DECL_DEFAULTED_FN (decl)
+ /* For implicit instantiations of cdtors,
+if import_export_decl would use comdat linkage,
+make sure to use it right away, so that maybe_clone_body
+can use aliases.  See PR113208.  */
+ || (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)
+ && (flag_implicit_templates
+ || flag_implicit_inline_templates)
+ && flag_weak
+ && TARGET_SUPPORTS_ALIASES)))


It seems wrong to set DECL_INTERFACE_KNOWN for cdtors that might get an 
explicit instantiation later, and likewise for comdat_linkage when 
!flag_weak; instead of adding this condition to the if, how about adding 
an else like



  else if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl))
/* For implicit instantiations of cdtors,
   if import_export_decl would use comdat linkage,   
   make sure to use it right away, so that maybe_clone_body  
   can use aliases.  See PR113208.  */

maybe_make_one_only (decl);


?

Jason



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

2024-04-24 Thread Jason Merrill

On 4/24/24 13:22, Patrick Palka wrote:

Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
does this look OK if successful?

-- >8 --

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

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

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

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

and afterward we print

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

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..a7067d4d2ed 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
  }
gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
diagnostic_show_locus (context, _loc, DK_NOTE);
+  context->printer->prefix = saved_prefix;


I would follow the pattern of c_diagnostic_finalizer here, i.e. using 
pp_set_prefix for the restore.


Though I think the pp_set_prefix to NULL in c_diagnostic_finalizer is 
redundant and should have been removed in r9-2240-g653fee1961981f when 
the previous line changed from _set_ to _take_.  If it isn't redundant, 
then it should be, i.e. pp_take_prefix should call it instead of 
directly setting NULL.


Some _take_ callers do set(NULL) and others don't; they should 
definitely be consistent one way or the other.


David, what do you think?

Jason



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

2024-04-24 Thread Jason Merrill

On 4/24/24 05:49, Patrick Palka wrote:

On Tue, 23 Apr 2024, Jason Merrill wrote:


On 4/23/24 11:28, Patrick Palka wrote:

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?


Is the test being run for multiple standard levels?  I'd rather restrict it to
one and keep fully testing GC-safety.


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


OK.


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

-- >8 --

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

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

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

gcc/testsuite/ChangeLog:

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

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

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




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

2024-04-23 Thread Jason Merrill

On 4/23/24 11:28, Patrick Palka wrote:

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?


Is the test being run for multiple standard levels?  I'd rather restrict 
it to one and keep fully testing GC-safety.



-- >8 --

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

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

gcc/testsuite/ChangeLog:

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

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

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




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

2024-04-23 Thread Jason Merrill

On 4/23/24 09:41, Patrick Palka wrote:

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

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

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

PR c++/114795

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d94d8ff4df9..e10e19ac9f7 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11537,6 +11537,11 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
   && !comp_except_specs (d_spec, e_spec, ce_type))
goto mismatch;
+
+  /* Similarly if EXISTING has an undeduced return type, but DECL's
+is already deduced.  */
+  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
+   TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);


Perhaps this should dump a note like the noexcept merge does?  OK either 
way.


Jason



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

2024-04-23 Thread Jason Merrill

On 4/21/24 19:59, Patrick Palka wrote:

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

-- >8 --

This fixes a null dereference issue when decl_specifiers.type is not yet
provided.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_parameter_declaration): Check if
decl_specifiers.type is null.

gcc/testsuite/ChangeLog:

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


LGTM


Yes, OK.




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

2024-04-22 Thread Jason Merrill

On 4/21/24 19:59, Patrick Palka wrote:

On Sat, 20 Apr 2024, Nathaniel Shead wrote:


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

-- >8 --

A class allocation member function is implicitly 'static' by
[class.free] p3, so cannot have an explicit object parameter.

PR c++/114078

gcc/cp/ChangeLog:

* decl.cc (grokdeclarator): Check allocation functions for xobj
parameters.

gcc/testsuite/ChangeLog:

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


LGTM


Agreed, OK.



Re: [PATCH] c++, v2: Retry the aliasing of base/complete cdtor optimization at import_export_decl time [PR113208]

2024-04-22 Thread Jason Merrill

On 4/22/24 08:42, Jakub Jelinek wrote:

On Wed, Apr 17, 2024 at 09:42:47AM +0200, Jakub Jelinek wrote:

When expand_or_defer_fn is called at_eof time, it calls import_export_decl
and then maybe_clone_body, which uses DECL_ONE_ONLY and comdat name in a
couple of places to try to optimize cdtors which are known to have the
same body by making the complete cdtor an alias to base cdtor (and in
that case also uses *[CD]5* as comdat group name instead of the normal
comdat group names specific to each mangled name).
Now, this optimization depends on DECL_ONE_ONLY and DECL_INTERFACE_KNOWN,
maybe_clone_body and can_alias_cdtor use:
   if (DECL_ONE_ONLY (fn))
 cgraph_node::get_create (clone)->set_comdat_group (cxx_comdat_group 
(clone));
...
   bool can_alias = can_alias_cdtor (fn);
...
   /* Tell cgraph if both ctors or both dtors are known to have
  the same body.  */
   if (can_alias
   && fns[0]
   && idx == 1
   && cgraph_node::get_create (fns[0])->create_same_body_alias
(clone, fns[0]))
 {
   alias = true;
   if (DECL_ONE_ONLY (fns[0]))
 {
   /* For comdat base and complete cdtors put them
  into the same, *[CD]5* comdat group instead of
  *[CD][12]*.  */
   comdat_group = cdtor_comdat_group (fns[1], fns[0]);
   cgraph_node::get_create (fns[0])->set_comdat_group 
(comdat_group);
   if (symtab_node::get (clone)->same_comdat_group)
 symtab_node::get (clone)->remove_from_same_comdat_group ();
   symtab_node::get (clone)->add_to_same_comdat_group
 (symtab_node::get (fns[0]));
 }
 }
and
   /* Don't use aliases for weak/linkonce definitions unless we can put both
  symbols in the same COMDAT group.  */
   return (DECL_INTERFACE_KNOWN (fn)
   && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn))
   && (!DECL_ONE_ONLY (fn)
   || (HAVE_COMDAT_GROUP && DECL_WEAK (fn;
The following testcase regressed with Marek's r14-5979 change,
when pr113208_0.C is compiled where the ctor is marked constexpr,
we no longer perform this optimization, where
_ZN6vectorI12QualityValueEC2ERKS1_ was emitted in the
_ZN6vectorI12QualityValueEC5ERKS1_ comdat group and
_ZN6vectorI12QualityValueEC1ERKS1_ was made an alias to it,
instead we emit _ZN6vectorI12QualityValueEC2ERKS1_ in
_ZN6vectorI12QualityValueEC2ERKS1_ comdat group and the same
content _ZN6vectorI12QualityValueEC1ERKS1_ as separate symbol in
_ZN6vectorI12QualityValueEC1ERKS1_ comdat group.


This seems like an ABI bug that could use a non-LTO testcase.


Now, the linker seems to somehow cope with that, eventhough it
probably keeps both copies of the ctor, but seems LTO can't cope
with that and Honza doesn't know what it should do in that case
(linker decides that the prevailing symbol is
_ZN6vectorI12QualityValueEC2ERKS1_ (from the
_ZN6vectorI12QualityValueEC2ERKS1_ comdat group) and
_ZN6vectorI12QualityValueEC1ERKS1_ alias (from the other TU,
from _ZN6vectorI12QualityValueEC5ERKS1_ comdat group)).

Note, the case where some constructor is marked constexpr in one
TU and not in another one happens pretty often in libstdc++ when
one mixes -std= flags used to compile different compilation units.

The reason the optimization doesn't trigger when the constructor is
constexpr is that expand_or_defer_fn is called in that case much earlier
than when it is not constexpr; in the former case it is called when we
try to constant evaluate that constructor.  But DECL_INTERFACE_KNOWN
is false in that case and comdat_linkage hasn't been called either
(I think it is desirable, because comdat group is stored in the cgraph
node and am not sure it is a good idea to create cgraph nodes for
something that might not be needed later on at all), so maybe_clone_body
clones the bodies, but doesn't make them as aliases.


Hmm, cloning the bodies and then discarding them later seems like more 
extra work than creating the cgraph nodes.


Jason



Re: [PATCH] c++: Copy over DECL_DISREGARD_INLINE_LIMITS flag to inheriting ctors [PR114784]

2024-04-22 Thread Jason Merrill

On 4/22/24 08:54, Jakub Jelinek wrote:

Hi!

The following testcase is rejected with
error: inlining failed in call to 'always_inline' '...': call is unlikely and 
code size would grow
errors.  The problem is that starting with the r14-2149 change
we try to copy most of the attributes from the inherited to
inheriting ctor, but don't copy associated flags that decl_attributes
sets.

Now, the other clone_attrs user, cp/optimize.cc (maybe_clone_body)
copies over
   DECL_COMDAT (clone) = DECL_COMDAT (fn);
   DECL_WEAK (clone) = DECL_WEAK (fn);
   if (DECL_ONE_ONLY (fn))
 cgraph_node::get_create (clone)->set_comdat_group (cxx_comdat_group 
(clone));
   DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
   DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
   DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
   DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
   DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
   DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);
   DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn);
   DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn);
The following patch just copies DECL_DISREGARD_INLINE_LIMITS to fix
this exact bug, not really sure which other flags should be copied
and which shouldn't.
Plus there are tons of other flags, some of which might need to be copied
too, some of which might not, perhaps in both places, like:
DECL_UNINLINABLE, maybe DECL_PRESERVE_P, TREE_USED, maybe
DECL_USER_ALIGN/DECL_ALIGN, maybe DECL_WEAK, maybe
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT, DECL_NO_LIMIT_STACK.
TREE_READONLY, DECL_PURE_P, TREE_THIS_VOLATILE (for const, pure and
noreturn attributes) probably makes no sense, DECL_IS_RETURNS_TWICE neither
(returns_twice ctor?).  What about TREE_NOTHROW?
DECL_FUNCTION_SPECIFIC_OPTIMIZATION, DECL_FUNCTION_SPECIFIC_TARGET...

Anyway, another problem is that if inherited_ctor is a TEMPLATE_DECL, as
also can be seen in the using D::D; case in the testcase, then
DECL_ATTRIBUTES (fn) = clone_attrs (DECL_ATTRIBUTES (inherited_ctor));
attempts to copy the attributes from the TEMPLATE_DECL which doesn't have
them.  The following patch copies them from STRIP_TEMPLATE (inherited_ctor)
which does.  E.g. DECL_DECLARED_CONSTEXPR_P works fine as the macro
itself uses STRIP_TEMPLATE too, but not 100% sure about other macros used
on inherited_ctor earlier.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


OK.


Do you want to copy other flags (and which ones and in which places),
is that ok to be deferred till stage 1?


Most of the others don't seem like they should be copied, but rather 
determined from the function body as usual.  Maybe 
DECL_FUNCTION_SPECIFIC_TARGET would make sense.  Either way, it can wait 
for stage 1.



2024-04-22  Jakub Jelinek  

PR c++/114784
* method.cc (implicitly_declare_fn): Call clone_attrs
on DECL_ATTRIBUTES on STRIP_TEMPLATE (inherited_ctor) rather than
inherited_ctor.  Also copy DECL_DISREGARD_INLINE_LIMITS flag from it.

* g++.dg/cpp0x/inh-ctor39.C: New test.

--- gcc/cp/method.cc.jj 2024-04-20 00:02:56.702387748 +0200
+++ gcc/cp/method.cc2024-04-22 12:51:36.395722484 +0200
@@ -3307,8 +3307,11 @@ implicitly_declare_fn (special_function_
/* Copy constexpr from the inherited constructor even if the
 inheriting constructor doesn't satisfy the requirements.  */
constexpr_p = DECL_DECLARED_CONSTEXPR_P (inherited_ctor);
+  tree inherited_ctor_fn = STRIP_TEMPLATE (inherited_ctor);
/* Also copy any attributes.  */
-  DECL_ATTRIBUTES (fn) = clone_attrs (DECL_ATTRIBUTES (inherited_ctor));
+  DECL_ATTRIBUTES (fn) = clone_attrs (DECL_ATTRIBUTES (inherited_ctor_fn));
+  DECL_DISREGARD_INLINE_LIMITS (fn)
+   = DECL_DISREGARD_INLINE_LIMITS (inherited_ctor_fn);
  }
  
/* Add the "this" parameter.  */

--- gcc/testsuite/g++.dg/cpp0x/inh-ctor39.C.jj  2024-04-22 13:02:10.490836357 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/inh-ctor39.C 2024-04-22 13:01:50.088122255 
+0200
@@ -0,0 +1,55 @@
+// PR c++/114784
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-O2" }
+
+template 
+struct A {
+  [[gnu::always_inline]] A (int t) { foo ().bar (t, {}); }
+  [[gnu::always_inline]] A (long long t) { foo ().bar (t, {}); }
+  T foo ();
+};
+
+struct B : A {
+  using A::A;
+  [[gnu::always_inline]] B (long long v) : A (v) {}
+  template 
+  void bar (T &&, int);
+  char b;
+};
+
+struct C {
+  C (int v) : a(v) { }
+  C (long long v) : a(v) { }
+  B a;
+};
+
+static C
+baz ()
+{
+  C x(0);
+  C y(0LL);
+  return 0;
+}
+
+[[gnu::cold]] int
+qux ()
+{
+  baz ();
+  return 0;
+}
+
+template 
+struct D {
+  template 
+  [[gnu::always_inline]] D (T) { d = sizeof (T); }
+  D();
+  int d;
+};
+template 
+struct E : D {
+  using D::D;
+};
+
+E c = {};
+E d = 1;
+E e = 1.0;

Jakub





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

2024-04-22 Thread Jason Merrill

On 4/22/24 15:18, Patrick Palka wrote:

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk/13/12?


OK with a rationale comment.


-- >8 --

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

PR c++/114709

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

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




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

2024-04-12 Thread Jason Merrill

On 3/14/24 17:26, Marek Polacek wrote:


In the following patch, I'm taking a different tack.  I believe
we ought to use TARGET_EXPR_ELIDING_P.  The gimplify_arg bit I'm
talking about below is this:

   /* Also strip a TARGET_EXPR that would force an extra copy.  */
   if (TREE_CODE (*arg_p) == TARGET_EXPR)
 {
   tree init = TARGET_EXPR_INITIAL (*arg_p);
   if (init
   && !VOID_TYPE_P (TREE_TYPE (init)))
 *arg_p = init;
 }

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/13?

-- >8 --
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.


I tried the same thing to see what you mean, and that doesn't look like 
a regression to me, just a different (and more accurate) diagnostic.


But you're right that this patch is safer, and the other approach can 
wait for stage 1.  Will you queue that up?  In the mean time, this patch 
is OK.



I just realized this could also check !TARGET_EXPR_ELIDING_P; there's no point
to adding an eliding TARGET_EXPR into the pset.


...with this change.

Jason



Re: [PATCH] c++/modules: Setup aliases imported from modules [PR106820]

2024-04-12 Thread Jason Merrill

On 3/26/24 09:24, Nathaniel Shead wrote:


I wonder if more generally we need to be doing more work when importing
definitions from header units especially to handle all the work that
'make_rtl_for_nonlocal_decl' and 'rest_of_decl_compilation' would have
been performing. 


Can we just call those functions?


But this patch fixes at least one missing step.


OK.


PR c++/106820

gcc/cp/ChangeLog:

* module.cc (trees_in::decl_value): Assemble alias when needed.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr106820_a.H: New test.
* g++.dg/modules/pr106820_b.C: New test.

Signed-off-by: Nathaniel Shead 
---
  gcc/cp/module.cc  | 9 +
  gcc/testsuite/g++.dg/modules/pr106820_a.H | 5 +
  gcc/testsuite/g++.dg/modules/pr106820_b.C | 8 
  3 files changed, 22 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/modules/pr106820_a.H
  create mode 100644 gcc/testsuite/g++.dg/modules/pr106820_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 8aab9ea0bae..b4e3b38c6fe 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -217,6 +217,7 @@ Classes used:
  #include "dumpfile.h"
  #include "bitmap.h"
  #include "cgraph.h"
+#include "varasm.h"
  #include "tree-iterator.h"
  #include "cpplib.h"
  #include "mkdeps.h"
@@ -8302,6 +8303,14 @@ trees_in::decl_value ()
if (state->is_header ()
  && decl_tls_wrapper_p (decl))
note_vague_linkage_fn (decl);
+
+  /* Setup aliases for the declaration.  */
+  if (tree alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
+   {
+ alias = TREE_VALUE (TREE_VALUE (alias));
+ alias = get_identifier (TREE_STRING_POINTER (alias));
+ assemble_alias (decl, alias);
+   }
  }
else
  {
diff --git a/gcc/testsuite/g++.dg/modules/pr106820_a.H 
b/gcc/testsuite/g++.dg/modules/pr106820_a.H
new file mode 100644
index 000..7d32d4e5fc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr106820_a.H
@@ -0,0 +1,5 @@
+// PR c++/106820
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi {} }
+
+static int __gthrw___pthread_key_create() __attribute__((__weakref__("foo")));
diff --git a/gcc/testsuite/g++.dg/modules/pr106820_b.C 
b/gcc/testsuite/g++.dg/modules/pr106820_b.C
new file mode 100644
index 000..247fe26e778
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr106820_b.C
@@ -0,0 +1,8 @@
+// PR c++/106820
+// { dg-additional-options "-fmodules-ts" }
+
+import "pr106820_a.H";
+
+int main() {
+  __gthrw___pthread_key_create();
+}




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

2024-04-12 Thread Jason Merrill

On 3/26/24 09:44, Patrick Palka wrote:

On Thu, 7 Mar 2024, Jason Merrill wrote:


On 1/29/24 17:42, Patrick Palka wrote:

On Mon, 29 Jan 2024, Patrick Palka wrote:


On Fri, 26 Jan 2024, Jason Merrill wrote:


On 1/26/24 17:11, Jason Merrill wrote:

On 1/26/24 16:52, Jason Merrill wrote:

On 1/25/24 14:18, Patrick Palka wrote:

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/13?  This isn't a very satisfactory fix, but at least
it safely fixes these testcases I guess.  Note that there's
implementation disagreement about the second testcase, GCC always
accepted it but Clang/MSVC/icc reject it.


Because of trying to initialize int& from {c}; removing the extra
braces
makes it work everywhore.

https://eel.is/c++draft/dcl.init#list-3.10 says that we always
generate a
prvalue in this case, so perhaps we shouldn't recalculate if the
initializer is an init-list?


...but it seems bad to silently bind a const int& to a prvalue instead
of
directly to the reference returned by the operator, as clang does if
we add
const to the second testcase, so I think there's a defect in the
standard
here.


Perhaps bullet 3.9 should change to "...its referenced type is
reference-related to E or scalar, ..."


Maybe for now also disable the maybe_valid heuristics in the case of
an
init-list?


The first testcase is special because it's a C-style cast; seems
like the
maybe_valid = false heuristics should be disabled if c_cast_p.


Thanks a lot for the pointers.  IIUC c_cast_p and
LOOKUP_SHORTCUT_BAD_CONVS
should already be mutually exclusive, since the latter is set only when
computing argument conversions, so it shouldn't be necessary to check
c_cast_p.

I suppose we could disable the heuristic for init-lists, but after some
digging I noticed that the heuristics were originally in same spot they
are now until r5-601-gd02f620dc0bb3b moved them to get checked after
the recursive recalculation case in reference_binding, returning a bad
conversion instead of NULL.  (Then in r13-1755-g68f37670eff0b872 I moved
them back; IIRC that's why I felt confident that moving the checks was
safe.)
Thus we didn't always accept the second testcase, we only started doing so
in
GCC 5: https://godbolt.org/z/6nsEW14fh (sorry for missing this and saying
we
always accepted it)

And indeed the current order of checks seems consistent with that of
[dcl.init.ref]/5.  So I wonder if we don't instead want to "complete"
the NULL-to-bad-conversion adjustment in r5-601-gd02f620dc0bb3b and
do:

gcc/cp/ChangeLog:

* call.cc (reference_binding): Set bad_p according to
maybe_valid_p in the recursive case as well.  Remove
redundant gcc_assert.

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 9de0d77c423..c4158b2af37 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2033,8 +2033,8 @@ reference_binding (tree rto, tree rfrom, tree expr,
bool c_cast_p, int flags,
   sflags, complain);
if (!new_second)
  return bad_direct_conv ? bad_direct_conv : nullptr;
+   t->bad_p = !maybe_valid_p;


Oops, that should be |= not =.


Perhaps bullet 3.9 should change to "...its referenced type is
reference-related to E or scalar, ..."

conv = merge_conversion_sequences (t, new_second);
-   gcc_assert (maybe_valid_p || conv->bad_p);
return conv;
  }
   }

This'd mean we'd go back to rejecting the second testcase (only the
call, not the direct-init, interestingly enough), but that seems to be


In the second testcase, with the above fix initialize_reference silently
returns error_mark_node for the direct-init without issuing a
diagnostic, because in the error path convert_like doesn't find anything
wrong with the bad conversion.  So more changes need to be made if we
want to set bad_p in the recursive case of reference_binding it seems;
dunno if that's the path we want to go down?

On the other hand, disabling the badness checks in certain cases seems
to be undesirable as well, since AFAICT their current position is
consistent with [dcl.init.ref]/5?

So I wonder if we should just go with the safest thing at this stage,
which would be the original patch that removes the problematic assert?


I still think the assert is correct, and the problem is that maybe_valid_p is
wrong; these cases turn out to be valid, so maybe_valid_p should be true.


I'm afraid then I don't know how we can statically identify these cases
without actually performing the conversion, in light of the recursion :/
Do you mind taking this PR?  I don't feel well-versed enough with the
reference binding rules to tackle this adequately..


That ended up being a surprisingly deep dive, but I've now checked in 
separate fixes for the two cases.


Jason



[pushed] c++: reference cast, conversion fn [PR113141]

2024-04-12 Thread Jason Merrill
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

The second testcase in 113141 is a separate issue: we first decide that the
conversion is ill-formed, but then when recalculating the special c_cast_p
handling makes us think it's OK.  We don't want that, it should continue to
fall back to the reinterpret_cast interpretation.  And while we're here,
let's warn that we're not using the conversion function.

Note that the standard seems to say that in this case we should
treat (Matrix &) as const_cast(static_cast(X)),
which would use the conversion operator, but that doesn't match existing
practice, so let's resolve that another day.  I've raised this issue with
CWG; at the moment I lean toward never binding a temporary in a C-style cast
to reference type, which would also be a change from existing practice.

PR c++/113141

gcc/c-family/ChangeLog:

* c.opt: Add -Wcast-user-defined.

gcc/ChangeLog:

* doc/invoke.texi: Document -Wcast-user-defined.

gcc/cp/ChangeLog:

* call.cc (reference_binding): For an invalid cast, warn and don't
recalculate.

gcc/testsuite/ChangeLog:

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

Co-authored-by: Patrick Palka 
---
 gcc/doc/invoke.texi | 13 +
 gcc/c-family/c.opt  |  4 
 gcc/cp/call.cc  | 12 +++-
 gcc/testsuite/g++.dg/conversion/ref12.C | 20 
 4 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/ref12.C

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5d5e70c3033..e3285587e4e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -9391,6 +9391,19 @@ In a cast involving pointer to member types this warning 
warns whenever
 the type cast is changing the pointer to member type.
 This warning is enabled by @option{-Wextra}.
 
+@opindex Wcast-user-defined
+@opindex Wno-cast-user-defined
+@item -Wcast-user-defined
+Warn when a cast to reference type does not involve a user-defined
+conversion that the programmer might expect to be called.
+
+@smallexample
+struct A @{ operator const int&(); @} a;
+auto r = (int&)a; // warning
+@end smallexample
+
+This warning is enabled by default.
+
 @opindex Wwrite-strings
 @opindex Wno-write-strings
 @item -Wwrite-strings
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 56cccf2a67b..848c2fda203 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -514,6 +514,10 @@ Wcast-qual
 C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
 Warn about casts which discard qualifiers.
 
+Wcast-user-defined
+C++ ObjC++ Var(warn_cast_user_defined) Warning Init(1)
+Warn about a cast to reference type that does not use a related user-defined 
conversion function.
+
 Wcatch-value
 C++ ObjC++ Warning Alias(Wcatch-value=, 1, 0)
 Warn about catch handlers of non-reference type.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 15b5647298e..dbdd7c29fe8 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2034,7 +2034,17 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
 recalculate the second conversion sequence.  */
   for (conversion *t = conv; t; t = next_conversion (t))
if (t->kind == ck_user
-   && DECL_CONV_FN_P (t->cand->fn))
+   && c_cast_p && !maybe_valid_p)
+ {
+   if (complain & tf_warning)
+ warning (OPT_Wcast_user_defined,
+  "casting %qT to %qT does not use %qD",
+  from, rto, t->cand->fn);
+   /* Don't let recalculation try to make this valid.  */
+   break;
+ }
+   else if (t->kind == ck_user
+&& DECL_CONV_FN_P (t->cand->fn))
  {
tree ftype = TREE_TYPE (TREE_TYPE (t->cand->fn));
/* A prvalue of non-class type is cv-unqualified.  */
diff --git a/gcc/testsuite/g++.dg/conversion/ref12.C 
b/gcc/testsuite/g++.dg/conversion/ref12.C
new file mode 100644
index 000..27ed9122769
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref12.C
@@ -0,0 +1,20 @@
+// PR c++/113141
+
+struct Matrix { };
+
+struct TPoint3 { private: operator const Matrix(); };
+
+void f(Matrix&);
+
+int main() {
+  TPoint3 X;
+  Matrix& m = (Matrix &)X; // { dg-warning "does not use" }
+  f((Matrix &)X);  // { dg-warning "does not use" }
+}
+
+struct A { private: operator const int&(); } a;
+int  = (int&)a;  // { dg-warning "does not use" }
+
+struct B { B(int); };
+int i;
+B  = (B&)i; // { dg-warning "does not use" }

base-commit: 0fd824d717ca901319864a5eeba4e62b278f8329
-- 
2.44.0



[pushed] c++: reference list-init, conversion fn [PR113141]

2024-04-12 Thread Jason Merrill
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

The original testcase in PR113141 is an instance of CWG1996; the standard
fails to consider conversion functions when initializing a reference
directly from an initializer-list of one element, but then does consider
them when initializing a temporary.  I have a proposed fix for this defect,
which is implemented here.

DR 1996
PR c++/113141

gcc/cp/ChangeLog:

* call.cc (reference_binding): Check direct binding from
a single-element list.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/initlist-ref1.C: New test.
* g++.dg/cpp0x/initlist-ref2.C: New test.
* g++.dg/cpp0x/initlist-ref3.C: New test.

Co-authored-by: Patrick Palka 
---
 gcc/cp/call.cc | 21 +
 gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C | 16 
 gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C | 10 ++
 gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C | 13 +
 4 files changed, 56 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 9568b5eb2c4..15b5647298e 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -1596,7 +1596,9 @@ standard_conversion (tree to, tree from, tree expr, bool 
c_cast_p,
   return conv;
 }
 
-/* Returns nonzero if T1 is reference-related to T2.  */
+/* Returns nonzero if T1 is reference-related to T2.
+
+   This is considered when a reference to T1 is initialized by a T2.  */
 
 bool
 reference_related_p (tree t1, tree t2)
@@ -1757,6 +1759,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
 }
 
   bool copy_list_init = false;
+  bool single_list_conv = false;
   if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
 {
   maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
@@ -1783,6 +1786,11 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
  from = etype;
  goto skip;
}
+ else if (CLASS_TYPE_P (etype) && TYPE_HAS_CONVERSION (etype))
+   /* CWG1996: jason's proposed drafting adds "or initializing T from E
+  would bind directly".  We check that in the direct binding with
+  conversion code below.  */
+   single_list_conv = true;
}
   /* Otherwise, if T is a reference type, a prvalue temporary of the type
 referenced by T is copy-list-initialized, and the reference is bound
@@ -1907,9 +1915,14 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
  (possibly cv-qualified) object to the (possibly cv-qualified) same
  object type (or a reference to it), to a (possibly cv-qualified) base
  class of that type (or a reference to it) */
-  else if (CLASS_TYPE_P (from) && !related_p
-  && !(flags & LOOKUP_NO_CONVERSION))
+  else if (!related_p
+  && !(flags & LOOKUP_NO_CONVERSION)
+  && (CLASS_TYPE_P (from) || single_list_conv))
 {
+  tree rexpr = expr;
+  if (single_list_conv)
+   rexpr = CONSTRUCTOR_ELT (expr, 0)->value;
+
   /* [dcl.init.ref]
 
 If the initializer expression
@@ -1923,7 +1936,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
 
the reference is bound to the lvalue result of the conversion
in the second case.  */
-  z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags,
+  z_candidate *cand = build_user_type_conversion_1 (rto, rexpr, flags,
complain);
   if (cand)
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
new file mode 100644
index 000..f893f12dafa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
@@ -0,0 +1,16 @@
+// PR c++/113141
+// { dg-do compile { target c++11 } }
+
+struct ConvToRef {
+  operator int&();
+};
+
+struct A { int& r; };
+
+void f(A);
+
+int main() {
+  ConvToRef c;
+  A a{{c}};
+  f({{c}});
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C
new file mode 100644
index 000..401d868d820
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C
@@ -0,0 +1,10 @@
+// CWG1996
+// { dg-do compile { target c++11 } }
+
+struct S { operator struct D &(); } s;
+D {s};   // OK, direct binding
+
+namespace N1 {
+  struct S { operator volatile struct D &(); } s;
+  const D {s};// { dg-error "invalid user-defined|discards qualifiers" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C
new file mode 100644
index 000..e2cc1deace5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C
@@ -0,0 

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-04-12 Thread Jason Merrill

On 4/12/24 14:39, Patrick Palka wrote:

On Fri, 12 Apr 2024, Jason Merrill wrote:


On 4/12/24 13:48, Patrick Palka wrote:

On Fri, 12 Apr 2024, Jason Merrill wrote:


On 4/12/24 10:35, Patrick Palka wrote:

On Wed, 10 Apr 2024, Jason Merrill wrote:


On 4/10/24 14:48, Patrick Palka wrote:

On Tue, 9 Apr 2024, Jason Merrill wrote:


On 3/5/24 10:31, Patrick Palka wrote:

On Tue, 27 Feb 2024, Patrick Palka wrote:

Subject: [PATCH] c++/modules: local type merging [PR99426]

One known missing piece in the modules implementation is merging
of
a
streamed-in local type (class or enum) with the corresponding
in-TU
version of the local type.  This missing piece turns out to
cause a
hard-to-reduce use-after-free GC issue due to the entity_ary not
being
marked as a GC root (deliberately), and manifests as a
serialization
error on stream-in as in PR99426 (see comment #6 for a
reduction).
It's
also reproducible on trunk when running the xtreme-header tests
without
-fno-module-lazy.

This patch makes us merge such local types according to their
position
within the containing function's definition, analogous to how we
merge
FIELD_DECLs of a class according to their index in the
TYPE_FIELDS
list.

PR c++/99426

gcc/cp/ChangeLog:

* module.cc (merge_kind::MK_local_type): New enumerator.
(merge_kind_name): Update.
(trees_out::chained_decls): Move BLOCK-specific handling
of DECL_LOCAL_DECL_P decls to ...
(trees_out::core_vals) : ... here.  Stream
BLOCK_VARS manually.
(trees_in::core_vals) : Stream BLOCK_VARS
manually.  Handle deduplicated local types..
(trees_out::key_local_type): Define.
(trees_in::key_local_type): Define.
(trees_out::get_merge_kind) : Return
MK_local_type for a local type.
(trees_out::key_mergeable) : Use
key_local_type.
(trees_in::key_mergeable) : Likewise.
(trees_in::is_matching_decl): Be flexible with type mismatches
for local entities.

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 80b63a70a62..d9e34e9a4b9 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6714,7 +6720,37 @@ trees_in::core_vals (tree t)
  case BLOCK:
t->block.locus = state->read_location (*this);
t->block.end_locus = state->read_location (*this);
-  t->block.vars = chained_decls ();
+
+  for (tree *chain = >block.vars;;)
+   if (tree decl = tree_node ())
+ {
+   /* For a deduplicated local type or enumerator, chain the
+  duplicate decl instead of the canonical in-TU decl.
Seeing
+  a duplicate here means the containing function whose
body
+  we're streaming in is a duplicate too, so we'll end up
+  discarding this BLOCK (and the rest of the duplicate
function
+  body) anyway.  */
+   if (is_duplicate (decl))
+ decl = maybe_duplicate (decl);
+   else if (DECL_IMPLICIT_TYPEDEF_P (decl)
+&& TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
+ {
+   tree tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl));
+   if (DECL_TEMPLATE_RESULT (tmpl) == decl &&
is_duplicate
(tmpl))
+ decl = DECL_TEMPLATE_RESULT (maybe_duplicate
(tmpl));
+ }


This seems like a lot of generally-applicable code for finding the
duplicate,
which other calls to maybe_duplicate/odr_duplicate don't use.  If
the
template
is a duplicate, why isn't its result?  If there's a good reason
for
that,
should this template handling go into maybe_duplicate?


Ah yeah, that makes sense.

Some context: IIUC modules treats the TEMPLATE_DECL instead of the
DECL_TEMPLATE_RESULT as the canonical decl, which in turn means
we'll
register_duplicate only the TEMPLATE_DECL.  But BLOCK_VARS never
contains
a TEMPLATE_DECL, always the DECL_TEMPLATE_RESULT (i.e. a TYPE_DECL),
hence the extra handling.

Given that it's relatively more difficult to get at the
TEMPLATE_DECL
from the DECL_TEMPLATE_RESULT rather than vice versa, maybe we
should
just register both as duplicates from register_duplicate?  That way
callers can just simply pass the DECL_TEMPLATE_RESULT to
maybe_duplicate
and it'll do the right thing.


Sounds good.


@@ -10337,6 +10373,83 @@ trees_in::fn_parms_fini (int tag, tree
fn,
tree
existing, bool is_defn)
  }
  }
  +/* Encode into KEY the position of the local type (class
or
enum)
+   declaration DECL within FN.  The position is encoded as the
+   index of the innermost BLOCK (numbered in BFS order) along
with
+   the index within its BLOCK_VARS list.  */


Since we already set DECL_DISCRIMINATOR for mangling, could we use
it+name
for
the key as well?


We could (and IIUc that'd be more robust to ODR violations), but
wouldn't it mean we'd have to do a linear walk over all BLOCK_VARs
of
all BLOCKS in order to find the one with the matching
name+discriminator?  That'd b

Re: [PATCH] c++: Fix constexpr evaluation of parameters passed by invisible reference [PR111284]

2024-04-12 Thread Jason Merrill

On 3/8/24 03:56, Jakub Jelinek wrote:

Hi!

My r9-6136 changes to make a copy of constexpr function bodies before
genericization modifies it broke the constant evaluation of non-POD
arguments passed by value.
In the callers such arguments are passed as reference to usually a
TARGET_EXPR, but on the callee side until genericization they are just
direct uses of a PARM_DECL with some class type.
In cxx_bind_parameters_in_call I've used convert_from_reference to
pretend it is passed by value and then cxx_eval_constant_expression
is called there and evaluates that as an rvalue, followed by
adjust_temp_type if the types don't match exactly (e.g. const Foo
argument and passing to it reference to Foo TARGET_EXPR).

The reason this doesn't work is that when the TARGET_EXPR in the caller
is constant initialized, this for it is the address of the TARGET_EXPR_SLOT,
but if the code later on pretends the PARM_DECL is just initialized to the
rvalue of the constant evaluation of the TARGET_EXPR, it is as if there
is a bitwise copy of the TARGET_EXPR to the callee, so this in the callee
is then address of the PARM_DECL in the callee.

The following patch attempts to fix that by constexpr evaluation of such
arguments in the caller as an lvalue instead of rvalue, and on the callee
side when seeing such a PARM_DECL, if we want an lvalue, lookup the value
(lvalue) saved in ctx->globals (if any), and if wanting an rvalue,
recursing with vc_prvalue on the looked up value (because it is there
as an lvalue, nor rvalue).

adjust_temp_type doesn't work for lvalues of non-scalarish types, for
such types it relies on changing the type of a CONSTRUCTOR, but on the
other side we know what we pass to the argument is addressable, so
the patch on type mismatch takes address of the argument value, casts
to reference to the desired type and dereferences it.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-03-08  Jakub Jelinek  

PR c++/111284
* constexpr.cc (cxx_bind_parameters_in_call): For PARM_DECLs with
TREE_ADDRESSABLE types use vc_glvalue rather than vc_prvalue for
cxx_eval_constant_expression and if it doesn't have the same
type as it should, cast the reference type to reference to type
before convert_from_reference and instead of adjust_temp_type
take address of the arg, cast to reference to type and then
convert_from_reference.
(cxx_eval_constant_expression) : For lval case
on parameters with TREE_ADDRESSABLE types lookup result in
ctx->globals if possible.  Otherwise if lookup in ctx->globals
was successful for parameter with TREE_ADDRESSABLE type,
recurse with vc_prvalue on the returned value.

* g++.dg/cpp1z/constexpr-111284.C: New test.
* g++.dg/cpp1y/constexpr-lifetime7.C: Expect one error on a different
line.

--- gcc/cp/constexpr.cc.jj  2024-02-13 10:29:57.979155641 +0100
+++ gcc/cp/constexpr.cc 2024-03-07 19:35:01.032412221 +0100
@@ -1877,13 +1877,21 @@ cxx_bind_parameters_in_call (const const
  x = build_address (x);
}
if (TREE_ADDRESSABLE (type))
-   /* Undo convert_for_arg_passing work here.  */
-   x = convert_from_reference (x);
-  /* Normally we would strip a TARGET_EXPR in an initialization context
-such as this, but here we do the elision differently: we keep the
-TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm.  */
-  arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
- non_constant_p, overflow_p);
+   {
+ /* Undo convert_for_arg_passing work here.  */
+ if (TYPE_REF_P (TREE_TYPE (x))
+ && !same_type_p (type, TREE_TYPE (TREE_TYPE (x
+   x = cp_fold_convert (build_reference_type (type), x);
+ x = convert_from_reference (x);
+ arg = cxx_eval_constant_expression (ctx, x, vc_glvalue,
+ non_constant_p, overflow_p);
+   }
+  else
+   /* Normally we would strip a TARGET_EXPR in an initialization context
+  such as this, but here we do the elision differently: we keep the
+  TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm.  */
+   arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
+   non_constant_p, overflow_p);


It seems simpler to move the convert_for_reference after the 
cxx_eval_constant_expression rather than duplicate the call to 
cxx_eval_constant_expression.



/* Check we aren't dereferencing a null pointer when calling a 
non-static
 member function, which is undefined behaviour.  */
if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun)
@@ -1909,7 +1917,16 @@ cxx_bind_parameters_in_call (const const
{
  /* Make sure the binding has the same type as the parm.  But
 only for constant args.  */
- 

Re: [PATCH] c++: Fix bogus warnings about ignored annotations [PR114409]

2024-04-12 Thread Jason Merrill

On 3/22/24 04:08, Jakub Jelinek wrote:

Hi!

The middle-end warns about the ANNOTATE_EXPR added for while/for loops
if they declare a var inside of the loop condition.
This is because the assumption is that ANNOTATE_EXPR argument is used
immediately in a COND_EXPR (later GIMPLE_COND), but simplify_loop_decl_cond
wraps the ANNOTATE_EXPR inside of a TRUTH_NOT_EXPR, so it no longer
holds.

The following patch fixes that by adding the TRUTH_NOT_EXPR inside of the
ANNOTATE_EXPR argument if any.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


OK


Note, the PR is mostly about ICE with the annotations used in a template,
this patch doesn't change anything on that and I really don't know what
should be done in that case.

2024-03-22  Jakub Jelinek  

PR c++/114409
* semantics.cc (simplify_loop_decl_cond): Use cp_build_unary_op with
TRUTH_NOT_EXPR on ANNOTATE_EXPR argument (if any) rather than
ANNOTATE_EXPR itself.

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

--- gcc/cp/semantics.cc.jj  2024-03-01 17:27:58.862888609 +0100
+++ gcc/cp/semantics.cc 2024-03-21 15:24:57.296857864 +0100
@@ -799,7 +799,11 @@ simplify_loop_decl_cond (tree *cond_p, t
*cond_p = boolean_true_node;
  
if_stmt = begin_if_stmt ();

-  cond = cp_build_unary_op (TRUTH_NOT_EXPR, cond, false, tf_warning_or_error);
+  cond_p = 
+  while (TREE_CODE (*cond_p) == ANNOTATE_EXPR)
+cond_p = _OPERAND (*cond_p, 0);
+  *cond_p = cp_build_unary_op (TRUTH_NOT_EXPR, *cond_p, false,
+  tf_warning_or_error);
finish_if_stmt_cond (cond, if_stmt);
finish_break_stmt ();
finish_then_clause (if_stmt);
--- gcc/testsuite/g++.dg/ext/pr114409.C.jj  2024-03-21 15:27:44.077661090 
+0100
+++ gcc/testsuite/g++.dg/ext/pr114409.C 2024-03-21 15:27:15.331039726 +0100
@@ -0,0 +1,22 @@
+// PR c++/114409
+// { dg-do compile }
+// { dg-options "-O2 -Wall" }
+
+void qux (int);
+int foo (int);
+
+void
+bar (int x)
+{
+  #pragma GCC novector
+  while (int y = foo (x))  // { dg-bogus "ignoring loop annotation" }
+qux (y);
+}
+
+void
+baz (int x)
+{
+  #pragma GCC novector
+  for (; int y = foo (x); )// { dg-bogus "ignoring loop annotation" }
+qux (y);
+}

Jakub





<    1   2   3   4   5   6   7   8   9   10   >