diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-12-04 14:51:32 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-12-04 14:51:32 -0800 |
commit | 945ae3ab27757d3261d99446f96105c5ebe70247 (patch) | |
tree | a8a120ef5393206d3bc9d2b5882bac1562824836 | |
parent | f012991e2db06cc95f7aac8ecb74a1ac5f51f3d2 (diff) | |
parent | 918a5b84a2c51dc9d011d39461cc276e6558069d (diff) | |
download | gcc-945ae3ab27757d3261d99446f96105c5ebe70247.zip gcc-945ae3ab27757d3261d99446f96105c5ebe70247.tar.gz gcc-945ae3ab27757d3261d99446f96105c5ebe70247.tar.bz2 |
Merge from trunk revision 918a5b84a2c51dc9d011d39461cc276e6558069d
84 files changed, 3847 insertions, 681 deletions
diff --git a/contrib/check-params-in-docs.py b/contrib/check-params-in-docs.py index dfbfa3d..440549f 100755 --- a/contrib/check-params-in-docs.py +++ b/contrib/check-params-in-docs.py @@ -23,6 +23,7 @@ # import argparse +import sys from itertools import dropwhile, takewhile @@ -42,7 +43,7 @@ parser.add_argument('params_output') args = parser.parse_args() -ignored = set(['logical-op-non-short-circuit']) +ignored = {'logical-op-non-short-circuit'} params = {} for line in open(args.params_output).readlines(): @@ -58,15 +59,21 @@ texi = list(texi)[1:] token = '@item ' texi = [x[len(token):] for x in texi if x.startswith(token)] +# skip digits +texi = [x for x in texi if not x[0].isdigit()] +# skip aarch64 params +texi = [x for x in texi if not x.startswith('aarch64')] sorted_texi = sorted(texi) texi_set = set(texi) - ignored params_set = set(params.keys()) - ignored +success = True extra = texi_set - params_set if len(extra): print('Extra:') print(extra) + success = False missing = params_set - texi_set if len(missing): @@ -75,6 +82,9 @@ if len(missing): print('@item ' + m) print(params[m]) print() + success = False if texi != sorted_texi: print('WARNING: not sorted alphabetically!') + +sys.exit(0 if success else 1) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7e76b2f..44dadd3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,189 @@ +2020-12-03 Martin Sebor <msebor@redhat.com> + + PR c++/90629 + PR middle-end/94527 + * builtins.c (access_ref::access_ref): Initialize new member. + (compute_objsize): Use access_ref::deref. Handle simple pointer + assignment. + (expand_builtin): Remove handling of the free built-in. + (call_dealloc_argno): Same. + (find_assignment_location): New function. + (fndecl_alloc_p): Same. + (gimple_call_alloc_p): Same. + (call_dealloc_p): Same. + (matching_alloc_calls_p): Same. + (warn_dealloc_offset): Same. + (maybe_emit_free_warning): Same. + * builtins.h (struct access_ref): Declare new member. + (maybe_emit_free_warning): Make extern. Make use of access_ref. + Handle -Wmismatched-new-delete. + * calls.c (initialize_argument_information): Call + maybe_emit_free_warning. + * doc/extend.texi (attribute malloc): Update. + * doc/invoke.texi (-Wfree-nonheap-object): Expand documentation. + (-Wmismatched-new-delete): Document new option. + (-Wmismatched-dealloc): Document new option. + +2020-12-03 Alexandre Oliva <oliva@adacore.com> + + * tree.c (build_common_builtin_nodes): Declare + __builtin___clear_cache for all languages. + * builtins.c (maybe_emit_call_builtin___clear_cache): Accept + Pmode arguments. + +2020-12-03 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * config/arm/t-rtems: Add "-mthumb -mcpu=cortex-r52 + -mfloat-abi=hard" multilib. + +2020-12-03 Uroš Bizjak <ubizjak@gmail.com> + Jakub Jelinek <jakub@redhat.com> + + PR target/98086 + * config/i386/i386.c (ix86_md_asm_adjustmd): Rewrite + zero-extension part to use convert_to_mode. + +2020-12-03 Andreas Krebbel <krebbel@linux.ibm.com> + + * config/s390/s390.md ("@probe_stack2<mode>"): Change mode + iterator to W. + +2020-12-03 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve-builtins-base.cc (svundef_impl::fold): + Delete. + +2020-12-03 Eric Botcazou <ebotcazou@adacore.com> + + PR middle-end/98099 + * expmed.c (flip_storage_order): In the case of a non-integer mode, + sorry out if the integer mode to be used instead is not supported. + +2020-12-03 Eric Botcazou <ebotcazou@adacore.com> + + PR middle-end/98082 + * function.c (use_register_for_decl): Also return true for a result + if cfun->tail_call_marked is true. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/93121 + * fold-const.h (native_encode_initializer): Add mask argument + defaulted to nullptr. + (find_bitfield_repr_type): Declare. + (native_interpret_aggregate): Declare. + * fold-const.c (find_bitfield_repr_type): New function. + (native_encode_initializer): Add mask argument and support for + filling it. Handle also some bitfields without integral + DECL_BIT_FIELD_REPRESENTATIVE. + (native_interpret_aggregate): New function. + * gimple-fold.h (clear_type_padding_in_mask): Declare. + * gimple-fold.c (struct clear_padding_struct): Add clear_in_mask + member. + (clear_padding_flush): Handle buf->clear_in_mask. + (clear_padding_union): Copy clear_in_mask. Don't error if + buf->clear_in_mask is set. + (clear_padding_type): Don't error if buf->clear_in_mask is set. + (clear_type_padding_in_mask): New function. + (gimple_fold_builtin_clear_padding): Set buf.clear_in_mask to false. + * doc/extend.texi (__builtin_bit_cast): Document. + +2020-12-03 Ilya Leoshkevich <iii@linux.ibm.com> + + * tree-ssa-threadedge.c (record_temporary_equivalences_from_stmts_at_dest): + Do not allow __builtin_constant_p on a threading path. + +2020-12-03 Ilya Leoshkevich <iii@linux.ibm.com> + + * tree-ssa-strlen.c (printf_strlen_execute): Avoid division by + 0. + +2020-12-03 Kito Cheng <kito.cheng@sifive.com> + + * config/riscv/multilib-generator (arch_canonicalize): Move + code to arch-canonicalize, and call that script to canonicalize arch + string. + (canonical_order): Move code to arch-canonicalize. + (LONG_EXT_PREFIXES): Ditto. + (IMPLIED_EXT): Ditto. + * config/riscv/arch-canonicalize: New. + * config.gcc (riscv*-*-*): Canonicalize --with-arch. + +2020-12-03 Przemyslaw Wirkus <przemyslaw.wirkus@arm.com> + + * config/aarch64/aarch64-option-extensions.def + (AARCH64_OPT_EXTENSION): New +flagm option in -march for AArch64. + * config/aarch64/aarch64.h (AARCH64_FL_FLAGM): Add new flagm extension bit + mask. + (AARCH64_FL_FOR_ARCH8_4): Add flagm to Armv8.4-A. + * doc/invoke.texi: Update docs with +flagm. + +2020-12-03 liuhongt <hongtao.liu@intel.com> + + PR target/96906 + * config/i386/sse.md + (<avx512>_ucmp<mode>3<mask_scalar_merge_name>): Add a new + define_split after this insn. + +2020-12-03 liuhongt <hongtao.liu@intel.com> + + PR target/97642 + * config/i386/i386-expand.c + (ix86_expand_special_args_builtin): Don't move all-ones mask + operands into register. + * config/i386/sse.md (UNSPEC_MASKLOAD): New unspec. + (*<avx512>_load<mode>_mask): New define_insns for masked load + instructions. + (<avx512>_load<mode>_mask): Changed to define_expands which + specifically handle memory or all-ones mask operands. + (<avx512>_blendm<mode>): Changed to define_insns which are same + as original <avx512>_load<mode>_mask with adjustment of + operands order. + (*<avx512>_load<mode>): New define_insn_and_split which is + used to optimize for masked load with all one mask. + +2020-12-03 Hongyu Wang <hongyu.wang@intel.com> + + PR target/97770 + * config/i386/sse.md (popcount<mode>2): New expander + for SI/DI vector modes. + (popcount<mode>2): Likewise for QI/HI vector modes. + +2020-12-03 Alexandre Oliva <oliva@adacore.com> + + * builtins.c (default_emit_call_builtin___clear_cache): New. + (maybe_emit_call_builtin___clear_cache): New. + (expand_builtin___clear_cache): Split into the above. + (expand_builtin): Do not issue clear_cache call any more. + * builtins.h (maybe_emit_call_builtin___clear_cache): Declare. + * config/aarch64/aarch64.c (aarch64_trampoline_init): Use + maybe_emit_call_builtin___clear_cache. + * config/arc/arc.c (arc_trampoline_init): Likewise. + * config/arm/arm.c (arm_trampoline_init): Likewise. + * config/c6x/c6x.c (c6x_initialize_trampoline): Likewise. + * config/csky/csky.c (csky_trampoline_init): Likewise. + * config/m68k/linux.h (FInALIZE_TRAMPOLINE): Likewise. + * config/tilegx/tilegx.c (tilegx_trampoline_init): Likewise. + * config/tilepro/tilepro.c (tilepro_trampoline_init): Ditto. + * config/vxworks.c: Include rtl.h, memmodel.h, and optabs.h. + (vxworks_emit_call_builtin___clear_cache): New. + * config/vxworks.h (CLEAR_INSN_CACHE): Drop. + (TARGET_EMIT_CALL_BUILTIN___CLEAR_CACHE): Define. + * target.def (trampoline_init): In the documentation, refer to + maybe_emit_call_builtin___clear_cache. + (emit_call_builtin___clear_cache): New. + * doc/tm.texi.in: Add new hook point. + (CLEAR_CACHE_INSN): Remove duplicate 'both'. + * doc/tm.texi: Rebuilt. + * targhooks.h (default_meit_call_builtin___clear_cache): + Declare. + * tree.h (BUILTIN_ASM_NAME_PTR): New. + +2020-12-03 Ilya Leoshkevich <iii@linux.ibm.com> + + * tree-ssa-threadbackward.c (thread_jumps::profitable_jump_thread_path): + Do not allow __builtin_constant_p on a threading path. + 2020-12-02 Jakub Jelinek <jakub@redhat.com> * dwarf2out.c (add_scalar_info): Only use add_AT_wide for 128-bit diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 81e21c8..3fac2aa 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20201203 +20201204 diff --git a/gcc/builtins.c b/gcc/builtins.c index cd30de8..bd12659 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -73,6 +73,7 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "omp-general.h" #include "tree-dfa.h" +#include "gimple-iterator.h" #include "gimple-ssa.h" #include "tree-ssa-live.h" #include "tree-outof-ssa.h" @@ -182,7 +183,6 @@ static rtx expand_builtin_memory_chk (tree, rtx, machine_mode, enum built_in_function); static void maybe_emit_chk_warning (tree, enum built_in_function); static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function); -static void maybe_emit_free_warning (tree); static tree fold_builtin_object_size (tree, tree); static bool check_read_access (tree, tree, tree = NULL_TREE, int = 1); static bool compute_objsize_r (tree, int, access_ref *, ssa_name_limit_t &, @@ -201,8 +201,8 @@ static void expand_builtin_sync_synchronize (void); access_ref::access_ref (tree bound /* = NULL_TREE */, bool minaccess /* = false */) -: ref (), eval ([](tree x){ return x; }), trail1special (true), base0 (true), - parmarray () +: ref (), eval ([](tree x){ return x; }), deref (), trail1special (true), + base0 (true), parmarray () { /* Set to valid. */ offrng[0] = offrng[1] = 0; @@ -5313,7 +5313,10 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref, const bool addr = TREE_CODE (ptr) == ADDR_EXPR; if (addr) - ptr = TREE_OPERAND (ptr, 0); + { + --pref->deref; + ptr = TREE_OPERAND (ptr, 0); + } if (DECL_P (ptr)) { @@ -5421,6 +5424,8 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref, if (code == ARRAY_REF || code == MEM_REF) { + ++pref->deref; + tree ref = TREE_OPERAND (ptr, 0); tree reftype = TREE_TYPE (ref); if (!addr && code == ARRAY_REF @@ -5544,6 +5549,10 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref, if (!compute_objsize_r (ref, ostype, pref, snlim, qry)) return false; + /* Clear DEREF since the offset is being applied to the target + of the dereference. */ + pref->deref = 0; + offset_int orng[2]; tree off = pref->eval (TREE_OPERAND (ptr, 1)); if (get_offset_range (off, NULL, orng, rvals)) @@ -10630,11 +10639,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, maybe_emit_sprintf_chk_warning (exp, fcode); break; - case BUILT_IN_FREE: - if (warn_free_nonheap_object) - maybe_emit_free_warning (exp); - break; - case BUILT_IN_THREAD_POINTER: return expand_builtin_thread_pointer (exp, target); @@ -12944,30 +12948,403 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) access_write_only); } -/* Emit warning if a free is called with address of a variable. */ +/* Return true if STMT is a call to an allocation function. Unless + ALL_ALLOC is set, consider only functions that return dynmamically + allocated objects. Otherwise return true even for all forms of + alloca (including VLA). */ -static void +static bool +fndecl_alloc_p (tree fndecl, bool all_alloc) +{ + if (!fndecl) + return false; + + /* A call to operator new isn't recognized as one to a built-in. */ + if (DECL_IS_OPERATOR_NEW_P (fndecl)) + return true; + + if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) + { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + return all_alloc; + case BUILT_IN_CALLOC: + case BUILT_IN_MALLOC: + case BUILT_IN_REALLOC: + case BUILT_IN_STRDUP: + case BUILT_IN_STRNDUP: + return true; + default: + break; + } + } + + /* A function is considered an allocation function if it's declared + with attribute malloc with an argument naming its associated + deallocation function. */ + tree attrs = DECL_ATTRIBUTES (fndecl); + if (!attrs) + return false; + + for (tree allocs = attrs; + (allocs = lookup_attribute ("malloc", allocs)); + allocs = TREE_CHAIN (allocs)) + { + tree args = TREE_VALUE (allocs); + if (!args) + continue; + + if (TREE_VALUE (args)) + return true; + } + + return false; +} + +/* Return true if STMT is a call to an allocation function. A wrapper + around fndecl_alloc_p. */ + +static bool +gimple_call_alloc_p (gimple *stmt, bool all_alloc = false) +{ + return fndecl_alloc_p (gimple_call_fndecl (stmt), all_alloc); +} + +/* Return the zero-based number corresponding to the argument being + deallocated if STMT is a call to a deallocation function or UINT_MAX + if it isn't. */ + +static unsigned +call_dealloc_argno (tree exp) +{ + tree fndecl = get_callee_fndecl (exp); + if (!fndecl) + return UINT_MAX; + + /* A call to operator delete isn't recognized as one to a built-in. */ + if (DECL_IS_OPERATOR_DELETE_P (fndecl)) + return 0; + + /* TODO: Handle user-defined functions with attribute malloc? Handle + known non-built-ins like fopen? */ + if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) + { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_FREE: + case BUILT_IN_REALLOC: + return 0; + default: + break; + } + return UINT_MAX; + } + + tree attrs = DECL_ATTRIBUTES (fndecl); + if (!attrs) + return UINT_MAX; + + for (tree atfree = attrs; + (atfree = lookup_attribute ("*dealloc", atfree)); + atfree = TREE_CHAIN (atfree)) + { + tree alloc = TREE_VALUE (atfree); + if (!alloc) + continue; + + tree pos = TREE_CHAIN (alloc); + if (!pos) + return 0; + + pos = TREE_VALUE (pos); + return TREE_INT_CST_LOW (pos) - 1; + } + + return UINT_MAX; +} + +/* Return true if STMT is a call to a deallocation function. */ + +static inline bool +call_dealloc_p (tree exp) +{ + return call_dealloc_argno (exp) != UINT_MAX; +} + +/* ALLOC_DECL and DEALLOC_DECL are pair of allocation and deallocation + functions. Return true if the latter is suitable to deallocate objects + allocated by calls to the former. */ + +static bool +matching_alloc_calls_p (tree alloc_decl, tree dealloc_decl) +{ + if (DECL_IS_OPERATOR_NEW_P (alloc_decl)) + { + if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl)) + { + /* Return true iff both functions are of the same array or + singleton form and false otherwise. */ + tree alloc_id = DECL_NAME (alloc_decl); + tree dealloc_id = DECL_NAME (dealloc_decl); + const char *alloc_fname = IDENTIFIER_POINTER (alloc_id); + const char *dealloc_fname = IDENTIFIER_POINTER (dealloc_id); + return !strchr (alloc_fname, '[') == !strchr (dealloc_fname, '['); + } + + /* Return false for deallocation functions that are known not + to match. */ + if (fndecl_built_in_p (dealloc_decl, BUILT_IN_FREE) + || fndecl_built_in_p (dealloc_decl, BUILT_IN_REALLOC)) + return false; + /* Otherwise proceed below to check the deallocation function's + "*dealloc" attributes to look for one that mentions this operator + new. */ + } + else if (fndecl_built_in_p (alloc_decl, BUILT_IN_NORMAL)) + { + switch (DECL_FUNCTION_CODE (alloc_decl)) + { + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + return false; + + case BUILT_IN_CALLOC: + case BUILT_IN_MALLOC: + case BUILT_IN_REALLOC: + case BUILT_IN_STRDUP: + case BUILT_IN_STRNDUP: + if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl)) + return false; + + if (fndecl_built_in_p (dealloc_decl, BUILT_IN_FREE) + || fndecl_built_in_p (dealloc_decl, BUILT_IN_REALLOC)) + return true; + break; + + default: + break; + } + } + + /* If DEALLOC_DECL has internal "*dealloc" attribute scan the list of + its associated allocation functions for ALLOC_DECL. If it's found + they are a matching pair, otherwise they're not. */ + tree attrs = DECL_ATTRIBUTES (dealloc_decl); + if (!attrs) + return false; + + for (tree funs = attrs; + (funs = lookup_attribute ("*dealloc", funs)); + funs = TREE_CHAIN (funs)) + { + tree args = TREE_VALUE (funs); + if (!args) + continue; + + tree fname = TREE_VALUE (args); + if (!fname) + continue; + + if (fname == DECL_NAME (alloc_decl)) + return true; + } + + return false; +} + +/* Return true if DEALLOC_DECL is a function suitable to deallocate + objectes allocated by the ALLOC call. */ + +static bool +matching_alloc_calls_p (gimple *alloc, tree dealloc_decl) +{ + tree alloc_decl = gimple_call_fndecl (alloc); + if (!alloc_decl) + return true; + + return matching_alloc_calls_p (alloc_decl, dealloc_decl); +} + +/* Diagnose a call to FNDECL to deallocate a pointer referenced by + AREF that includes a nonzero offset. Such a pointer cannot refer + to the beginning of an allocated object. A negative offset may + refer to it only if the target pointer is unknown. */ + +static bool +warn_dealloc_offset (location_t loc, tree exp, tree fndecl, + const access_ref &aref) +{ + char offstr[80]; + offstr[0] = '\0'; + if (wi::fits_shwi_p (aref.offrng[0])) + { + if (aref.offrng[0] == aref.offrng[1] + || !wi::fits_shwi_p (aref.offrng[1])) + sprintf (offstr, " %lli", + (long long)aref.offrng[0].to_shwi ()); + else + sprintf (offstr, " [%lli, %lli]", + (long long)aref.offrng[0].to_shwi (), + (long long)aref.offrng[1].to_shwi ()); + } + + if (!warning_at (loc, OPT_Wfree_nonheap_object, + "%K%qD called on pointer %qE with nonzero offset%s", + exp, fndecl, aref.ref, offstr)) + return false; + + if (DECL_P (aref.ref)) + inform (DECL_SOURCE_LOCATION (aref.ref), "declared here"); + else if (TREE_CODE (aref.ref) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (aref.ref); + if (is_gimple_call (def_stmt)) + { + tree alloc_decl = gimple_call_fndecl (def_stmt); + inform (gimple_location (def_stmt), + "returned from a call to %qD", alloc_decl); + } + } + + return true; +} + +/* Issue a warning if a deallocation function such as free, realloc, + or C++ operator delete is called with an argument not returned by + a matching allocation function such as malloc or the corresponding + form of C++ operatorn new. */ + +void maybe_emit_free_warning (tree exp) { - if (call_expr_nargs (exp) != 1) + tree fndecl = get_callee_fndecl (exp); + if (!fndecl) return; - tree arg = CALL_EXPR_ARG (exp, 0); + unsigned argno = call_dealloc_argno (exp); + if ((unsigned) call_expr_nargs (exp) <= argno) + return; - STRIP_NOPS (arg); - if (TREE_CODE (arg) != ADDR_EXPR) + tree ptr = CALL_EXPR_ARG (exp, argno); + if (integer_zerop (ptr)) return; - arg = get_base_address (TREE_OPERAND (arg, 0)); - if (arg == NULL || INDIRECT_REF_P (arg) || TREE_CODE (arg) == MEM_REF) + access_ref aref; + if (!compute_objsize (ptr, 0, &aref)) return; - if (SSA_VAR_P (arg)) - warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object, - "%Kattempt to free a non-heap object %qD", exp, arg); - else - warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object, - "%Kattempt to free a non-heap object", exp); + tree ref = aref.ref; + if (integer_zerop (ref)) + return; + + tree dealloc_decl = get_callee_fndecl (exp); + location_t loc = tree_nonartificial_location (exp); + loc = expansion_point_location_if_in_system_header (loc); + + if (DECL_P (ref) || EXPR_P (ref)) + { + /* Diagnose freeing a declared object. */ + if (aref.ref_declared () + && warning_at (loc, OPT_Wfree_nonheap_object, + "%K%qD called on unallocated object %qD", + exp, dealloc_decl, ref)) + { + inform (DECL_SOURCE_LOCATION (ref), + "declared here"); + return; + } + + /* Diagnose freeing a pointer that includes a positive offset. + Such a pointer cannot refer to the beginning of an allocated + object. A negative offset may refer to it. */ + if (!aref.deref + && aref.sizrng[0] != aref.sizrng[1] + && aref.offrng[0] > 0 && aref.offrng[1] > 0 + && warn_dealloc_offset (loc, exp, dealloc_decl, aref)) + return; + } + else if (CONSTANT_CLASS_P (ref)) + { + if (warning_at (loc, OPT_Wfree_nonheap_object, + "%K%qD called on a pointer to an unallocated " + "object %qE", exp, dealloc_decl, ref)) + { + if (TREE_CODE (ptr) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (ptr); + if (is_gimple_assign (def_stmt)) + { + location_t loc = gimple_location (def_stmt); + inform (loc, "assigned here"); + } + } + return; + } + } + else if (TREE_CODE (ref) == SSA_NAME) + { + /* Also warn if the pointer argument refers to the result + of an allocation call like alloca or VLA. */ + gimple *def_stmt = SSA_NAME_DEF_STMT (ref); + if (is_gimple_call (def_stmt)) + { + bool warned = false; + if (gimple_call_alloc_p (def_stmt)) + { + if (matching_alloc_calls_p (def_stmt, dealloc_decl)) + { + if (!aref.deref + && aref.offrng[0] > 0 && aref.offrng[1] > 0 + && warn_dealloc_offset (loc, exp, dealloc_decl, aref)) + return; + } + else + { + tree alloc_decl = gimple_call_fndecl (def_stmt); + int opt = (DECL_IS_OPERATOR_NEW_P (alloc_decl) + || DECL_IS_OPERATOR_DELETE_P (dealloc_decl) + ? OPT_Wmismatched_new_delete + : OPT_Wmismatched_dealloc); + warned = warning_at (loc, opt, + "%K%qD called on pointer returned " + "from a mismatched allocation " + "function", exp, dealloc_decl); + } + } + else if (gimple_call_builtin_p (def_stmt, BUILT_IN_ALLOCA) + || gimple_call_builtin_p (def_stmt, + BUILT_IN_ALLOCA_WITH_ALIGN)) + warned = warning_at (loc, OPT_Wfree_nonheap_object, + "%K%qD called on pointer to " + "an unallocated object", + exp, dealloc_decl); + else if (!aref.deref + && aref.offrng[0] > 0 && aref.offrng[1] > 0 + && warn_dealloc_offset (loc, exp, dealloc_decl, aref)) + return; + + if (warned) + { + tree fndecl = gimple_call_fndecl (def_stmt); + inform (gimple_location (def_stmt), + "returned from a call to %qD", fndecl); + return; + } + } + else if (gimple_nop_p (def_stmt)) + { + ref = SSA_NAME_VAR (ref); + /* Diagnose freeing a pointer that includes a positive offset. */ + if (TREE_CODE (ref) == PARM_DECL + && !aref.deref + && aref.sizrng[0] != aref.sizrng[1] + && aref.offrng[0] > 0 && aref.offrng[1] > 0 + && warn_dealloc_offset (loc, exp, dealloc_decl, aref)) + return; + } + } } /* Fold a call to __builtin_object_size with arguments PTR and OST, diff --git a/gcc/builtins.h b/gcc/builtins.h index 09379e8..6429232 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -220,6 +220,12 @@ struct access_ref argument to the minimum. */ offset_int size_remaining (offset_int * = NULL) const; + /* Return true if *THIS is an access to a declared object. */ + bool ref_declared () const + { + return DECL_P (ref) && base0 && deref < 1; + } + /* Set the size range to the maximum. */ void set_max_size_range () { @@ -261,6 +267,9 @@ struct access_ref /* Used to fold integer expressions when called from front ends. */ tree (*eval)(tree); + /* Positive when REF is dereferenced, negative when its address is + taken. */ + int deref; /* Set if trailing one-element arrays should be treated as flexible array members. */ bool trail1special; @@ -350,5 +359,6 @@ extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL, range_query * = NULL); extern bool check_access (tree, tree, tree, tree, tree, access_mode, const access_data * = NULL); +extern void maybe_emit_free_warning (tree); #endif /* GCC_BUILTINS_H */ diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 0421c98..2e88f20 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,18 @@ +2020-12-03 Martin Sebor <msebor@redhat.com> + + PR c++/90629 + PR middle-end/94527 + * c-attribs.c (handle_dealloc_attribute): New function. + (handle_malloc_attribute): Handle argument forms of attribute. + * c.opt (-Wmismatched-dealloc): New option. + (-Wmismatched-new-delete): New option. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/93121 + * c-common.h (enum rid): Add RID_BUILTIN_BIT_CAST. + * c-common.c (c_common_reswords): Add __builtin_bit_cast. + 2020-12-01 JeanHeyd Meneide <phdofthehouse@gmail.com> * c-cppbuiltin.c (c_cpp_builtins): Add predefined diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 99b6630..f7dad7a 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -113,6 +113,7 @@ static tree handle_no_instrument_function_attribute (tree *, tree, static tree handle_no_profile_instrument_function_attribute (tree *, tree, tree, int, bool *); static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree handle_dealloc_attribute (tree *, tree, tree, int, bool *); static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); static tree handle_no_limit_stack_attribute (tree *, tree, tree, int, bool *); @@ -364,7 +365,7 @@ const struct attribute_spec c_common_attribute_table[] = { "no_profile_instrument_function", 0, 0, true, false, false, false, handle_no_profile_instrument_function_attribute, NULL }, - { "malloc", 0, 0, true, false, false, false, + { "malloc", 0, 2, true, false, false, false, handle_malloc_attribute, attr_alloc_exclusions }, { "returns_twice", 0, 0, true, false, false, false, handle_returns_twice_attribute, @@ -524,6 +525,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_objc_root_class_attribute, NULL }, { "objc_nullability", 1, 1, true, false, false, false, handle_objc_nullability_attribute, NULL }, + { "*dealloc", 1, 2, true, false, false, false, + handle_dealloc_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -3127,20 +3130,179 @@ handle_no_profile_instrument_function_attribute (tree *node, tree name, tree, return NULL_TREE; } -/* Handle a "malloc" attribute; arguments as in - struct attribute_spec.handler. */ +/* Handle the "malloc" attribute. */ static tree -handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args), +handle_malloc_attribute (tree *node, tree name, tree args, int ARG_UNUSED (flags), bool *no_add_attrs) { - if (TREE_CODE (*node) == FUNCTION_DECL - && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) - DECL_IS_MALLOC (*node) = 1; - else + tree fndecl = *node; + + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored; valid only " + "for functions", + name); + *no_add_attrs = true; + return NULL_TREE; + } + + tree rettype = TREE_TYPE (TREE_TYPE (*node)); + if (!POINTER_TYPE_P (rettype)) + { + warning (OPT_Wattributes, "%qE attribute ignored on functions " + "returning %qT; valid only for pointer return types", + name, rettype); + *no_add_attrs = true; + return NULL_TREE; + } + + if (!args) + { + /* Only the form of the attribute with no arguments declares + a function malloc-like. */ + DECL_IS_MALLOC (*node) = 1; + return NULL_TREE; + } + + tree dealloc = TREE_VALUE (args); + if (error_operand_p (dealloc)) + { + /* If the argument is in error it will have already been diagnosed. + Avoid issuing redundant errors here. */ + *no_add_attrs = true; + return NULL_TREE; + } + + /* In C++ the argument may be wrapped in a cast to disambiguate one + of a number of overloads (such as operator delete). Strip it. */ + STRIP_NOPS (dealloc); + if (TREE_CODE (dealloc) == ADDR_EXPR) + dealloc = TREE_OPERAND (dealloc, 0); + + if (TREE_CODE (dealloc) != FUNCTION_DECL) + { + if (TREE_CODE (dealloc) == OVERLOAD) + { + /* Handle specially the common case of specifying one of a number + of overloads, such as operator delete. */ + error ("%qE attribute argument 1 is ambiguous", name); + inform (input_location, + "use a cast to the expected type to disambiguate"); + *no_add_attrs = true; + return NULL_TREE; + } + + error ("%qE attribute argument 1 does not name a function", name); + if (DECL_P (dealloc)) + inform (DECL_SOURCE_LOCATION (dealloc), + "argument references a symbol declared here"); + *no_add_attrs = true; + return NULL_TREE; + } + + /* Mentioning the deallocation function qualifies as its use. */ + TREE_USED (dealloc) = 1; + + tree fntype = TREE_TYPE (dealloc); + tree argpos = TREE_CHAIN (args) ? TREE_VALUE (TREE_CHAIN (args)) : NULL_TREE; + if (!argpos) + { + tree argtypes = TYPE_ARG_TYPES (fntype); + if (!argtypes) + { + /* Reject functions without a prototype. */ + error ("%qE attribute argument 1 must take a pointer " + "type as its first argument", name); + inform (DECL_SOURCE_LOCATION (dealloc), + "refernced symbol declared here" ); + *no_add_attrs = true; + return NULL_TREE; + } + + tree argtype = TREE_VALUE (argtypes); + if (TREE_CODE (argtype) != POINTER_TYPE) + { + /* Reject functions that don't take a pointer as their first + argument. */ + error ("%qE attribute argument 1 must take a pointer type " + "as its first argument; have %qT", name, argtype); + inform (DECL_SOURCE_LOCATION (dealloc), + "referenced symbol declared here" ); + *no_add_attrs = true; + return NULL_TREE; + } + + *no_add_attrs = false; + tree attr_free = build_tree_list (NULL_TREE, DECL_NAME (fndecl)); + attr_free = build_tree_list (get_identifier ("*dealloc"), attr_free); + decl_attributes (&dealloc, attr_free, 0); + return NULL_TREE; + } + + /* Validate the positional argument. */ + argpos = positional_argument (fntype, name, argpos, POINTER_TYPE); + if (!argpos) { - warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; + return NULL_TREE; + } + + /* It's valid to declare the same function with multiple instances + of attribute malloc, each naming the same or different deallocator + functions, and each referencing either the same or a different + positional argument. */ + *no_add_attrs = false; + tree attr_free = tree_cons (NULL_TREE, argpos, NULL_TREE); + attr_free = tree_cons (NULL_TREE, DECL_NAME (fndecl), attr_free); + attr_free = build_tree_list (get_identifier ("*dealloc"), attr_free); + decl_attributes (&dealloc, attr_free, 0); + return NULL_TREE; +} + +/* Handle the internal "*dealloc" attribute added for functions declared + with the one- and two-argument forms of attribute malloc. Add it + to *NODE unless it's already there with the same arguments. */ + +static tree +handle_dealloc_attribute (tree *node, tree name, tree args, int, + bool *no_add_attrs) +{ + tree fndecl = *node; + + tree attrs = DECL_ATTRIBUTES (fndecl); + if (!attrs) + return NULL_TREE; + + tree arg_fname = TREE_VALUE (args); + args = TREE_CHAIN (args); + tree arg_pos = args ? TREE_VALUE (args) : NULL_TREE; + + gcc_checking_assert (TREE_CODE (arg_fname) == IDENTIFIER_NODE); + + const char* const namestr = IDENTIFIER_POINTER (name); + for (tree at = attrs; (at = lookup_attribute (namestr, at)); + at = TREE_CHAIN (at)) + { + tree alloc = TREE_VALUE (at); + if (!alloc) + continue; + + tree pos = TREE_CHAIN (alloc); + alloc = TREE_VALUE (alloc); + pos = pos ? TREE_VALUE (pos) : NULL_TREE; + gcc_checking_assert (TREE_CODE (alloc) == IDENTIFIER_NODE); + + if (alloc == arg_fname + && ((!pos && !arg_pos) + || (pos && arg_pos && tree_int_cst_equal (pos, arg_pos)))) + { + /* The function already has the attribute either without any + arguments or with the same arguments as the attribute that's + being added. Return without adding another copy. */ + *no_add_attrs = true; + return NULL_TREE; + } } return NULL_TREE; diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 059f6c3..7947828 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -793,6 +793,16 @@ Wmisleading-indentation C C++ Common Var(warn_misleading_indentation) Warning LangEnabledBy(C C++,Wall) Warn when the indentation of the code does not reflect the block structure. +Wmismatched-dealloc +C ObjC C++ ObjC++ Var(warn_mismatched_alloc) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) +Warn for deallocation calls with arguments returned from mismatched allocation +functions. + +Wmismatched-new-delete +C++ ObjC++ Var(warn_mismatched_new_delete) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) +Warn for mismatches between calls to operator new or delete and the corrsponding +call to the allocation or deallocation function. + Wmismatched-tags C++ ObjC++ Var(warn_mismatched_tags) Warning Warn when a class is redeclared or referenced using a mismatched class-key. diff --git a/gcc/calls.c b/gcc/calls.c index a93d4bf..4114bf5 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2623,6 +2623,10 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, /* Check attribute access arguments. */ maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp); + + /* Check calls to operator new for mismatched forms and attempts + to deallocate unallocated objects. */ + maybe_emit_free_warning (exp); } /* Update ARGS_SIZE to contain the total size for the argument block. diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 7e0bdd5..f7b4091 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -5919,7 +5919,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) && !target_for_debug_bind (var)) goto delink_debug_stmt; - if (DECL_P (var)) + if (DECL_P (var) && !VECTOR_TYPE_P (TREE_TYPE (var))) mode = DECL_MODE (var); else mode = TYPE_MODE (TREE_TYPE (var)); @@ -5936,7 +5936,10 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) value = gimple_debug_source_bind_get_value (stmt); - mode = DECL_MODE (var); + if (!VECTOR_TYPE_P (TREE_TYPE (var))) + mode = DECL_MODE (var); + else + mode = TYPE_MODE (TREE_TYPE (var)); val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value, VAR_INIT_STATUS_UNINITIALIZED); diff --git a/gcc/common.opt b/gcc/common.opt index 582e2aa..6645539 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3178,6 +3178,14 @@ gdwarf- Common Driver Joined UInteger Var(dwarf_version) Init(4) Negative(gstabs) Generate debug information in DWARF v2 (or later) format. +gdwarf32 +Common Driver Var(dwarf_offset_size,4) Init(4) RejectNegative +Use 32-bit DWARF format when emitting DWARF debug information. + +gdwarf64 +Common Driver Var(dwarf_offset_size,8) RejectNegative +Use 64-bit DWARF format when emitting DWARF debug information. + ggdb Common Driver JoinedOrMissing Generate debug information in default extended format. diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 76e9499..129d47b 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -11975,6 +11975,23 @@ (clobber (reg:CC FLAGS_REG))])] "operands[2] = gen_lowpart (QImode, operands[2]);") +(define_split + [(set (match_operand:SWI48 0 "register_operand") + (any_rotate:SWI48 + (match_operand:SWI48 1 "const_int_operand") + (subreg:QI + (and:SI + (match_operand:SI 2 "register_operand") + (match_operand:SI 3 "const_int_operand")) 0)))] + "(INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) + == GET_MODE_BITSIZE (<MODE>mode) - 1" + [(set (match_dup 4) (match_dup 1)) + (set (match_dup 0) + (any_rotate:SWI48 (match_dup 4) + (subreg:QI + (and:SI (match_dup 2) (match_dup 3)) 0)))] + "operands[4] = gen_reg_rtx (<MODE>mode);") + (define_insn_and_split "*<rotate_insn><mode>3_mask_1" [(set (match_operand:SWI48 0 "nonimmediate_operand") (any_rotate:SWI48 @@ -11995,6 +12012,21 @@ (match_dup 2))) (clobber (reg:CC FLAGS_REG))])]) +(define_split + [(set (match_operand:SWI48 0 "register_operand") + (any_rotate:SWI48 + (match_operand:SWI48 1 "const_int_operand") + (and:QI + (match_operand:QI 2 "register_operand") + (match_operand:QI 3 "const_int_operand"))))] + "(INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) + == GET_MODE_BITSIZE (<MODE>mode) - 1" + [(set (match_dup 4) (match_dup 1)) + (set (match_dup 0) + (any_rotate:SWI48 (match_dup 4) + (and:QI (match_dup 2) (match_dup 3))))] + "operands[4] = gen_reg_rtx (<MODE>mode);") + ;; Implement rotation using two double-precision ;; shift instructions and a scratch register. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c661f7a..f26fc13 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -3864,6 +3864,12 @@ rs6000_option_override_internal (bool global_init_p) if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET) rs6000_print_isa_options (stderr, 0, "before defaults", rs6000_isa_flags); +#ifdef XCOFF_DEBUGGING_INFO + /* For AIX default to 64-bit DWARF. */ + if (!global_options_set.x_dwarf_offset_size) + dwarf_offset_size = POINTER_SIZE_UNITS; +#endif + /* Handle explicit -mno-{altivec,vsx,power8-vector,power9-vector} and turn off all of the options that depend on those flags. */ ignore_masks = rs6000_disable_incompatible_switches (); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6728ea1..1bf50cd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,70 @@ +2020-12-03 Jason Merrill <jason@redhat.com> + + * cp-tree.h (releasing_vec::operator[]): Change parameter type to + ptrdiff_t. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (OVL_EXPORT): New. + (class ovl_iterator): Add get_using, exporting_p. + * tree.c (ovl_insert): Extend using_or_hidden meaning to include + an exported using. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_UNINSTANTIATED_TEMPLATE_FRIEND): New. + * pt.c (push_template_decl): Set it. + (tsubst_friend_function): Clear it. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (make_unbound_class_template_raw): Declare. + (canonical_type_parameter): Declare. + * decl.c (make_unbound_class_template_raw): Break out of ... + (make_unboud_class_template): ... here. Call it. + * pt.c (canonical_type_parameter): Externalize. Refactor & set + structural_equality for type parms. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + PR c++/98107 + * tree.c (build_cplus_array_type): Mark dependency of new variant. + (cp_build_qualified_type_real, strip_typedefs): Assert + TYPE_DEPENDENT_P_VALID, or not a dependent type. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/93121 + * cp-tree.h (cp_build_bit_cast): Declare. + * cp-tree.def (BIT_CAST_EXPR): New tree code. + * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_BIT_CAST. + (cp_common_init_ts): Handle BIT_CAST_EXPR. + * cxx-pretty-print.c (cxx_pretty_printer::postfix_expression): + Likewise. + * parser.c (cp_parser_postfix_expression): Handle + RID_BUILTIN_BIT_CAST. + * semantics.c (cp_build_bit_cast): New function. + * tree.c (cp_tree_equal): Handle BIT_CAST_EXPR. + (cp_walk_subtrees): Likewise. + * pt.c (tsubst_copy): Likewise. + * constexpr.c (check_bit_cast_type, cxx_eval_bit_cast): New functions. + (cxx_eval_constant_expression): Handle BIT_CAST_EXPR. + (potential_constant_expression_1): Likewise. + * cp-gimplify.c (cp_genericize_r): Likewise. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * parser.c (cp_parser_primary_expression): Distinguish + parms from vars in error. + (cp_parser_late_parsing_default_args): Pushdecl parms + as we go. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * name-lookup.c (begin_scope): Set immediate_fn_ctx_p. + * parser.c (cp_parser_late_parsing_default_args): Push + sk_function_parms scope. + 2020-12-03 Peter Bergner <bergner@linux.ibm.com> PR c++/97947 diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index bafcaf5..8bbcf01 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -3005,7 +3005,7 @@ fold_builtin_source_location (location_t loc) const char *name = ""; if (current_function_decl) - name = cxx_printable_name (current_function_decl, 0); + name = cxx_printable_name (current_function_decl, 2); val = build_string_literal (strlen (name) + 1, name); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 69f8ed5..00901fe 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -488,10 +488,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; CALL_EXPR_ORDERED_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE) CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR) - DECL_MODULE_EXPORT_P (in _DECL) OVL_NESTED_P (in OVERLOAD) LAMBDA_EXPR_INSTANTIATED (in LAMBDA_EXPR) - Reserved for DECL_MODULE_EXPORT (in DECL_) + DECL_MODULE_EXPORT_P (in _DECL) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -503,6 +502,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) CONSTRUCTOR_PLACEHOLDER_BOUNDARY (in CONSTRUCTOR) + OVL_EXPORT_P (in OVERLOAD) 6: TYPE_MARKED_P (in _TYPE) DECL_NONTRIVIALLY_INITIALIZED_P (in VAR_DECL) RANGE_FOR_IVDEP (in RANGE_FOR_STMT) @@ -545,6 +545,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECL_ANON_UNION_VAR_P (in a VAR_DECL) DECL_SELF_REFERENCE_P (in a TYPE_DECL) DECL_INVALID_OVERRIDER_P (in a FUNCTION_DECL) + DECL_UNINSTANIATED_TEMPLATE_FRIEND_P (in TEMPLATE_DECL) 5: DECL_INTERFACE_KNOWN. 6: DECL_THIS_STATIC (in VAR_DECL, FUNCTION_DECL or PARM_DECL) DECL_FIELD_IS_BASE (in FIELD_DECL) @@ -779,6 +780,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t; #define OVL_NESTED_P(NODE) TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE)) /* If set, this overload was constructed during lookup. */ #define OVL_LOOKUP_P(NODE) TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE)) +/* If set, this OVL_USING_P overload is exported. */ +#define OVL_EXPORT_P(NODE) TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE)) /* The first decl of an overload. */ #define OVL_FIRST(NODE) ovl_first (NODE) @@ -838,6 +841,11 @@ class ovl_iterator { return fn; } + tree get_using () const + { + gcc_checking_assert (using_p ()); + return ovl; + } public: /* Whether this overload was introduced by a using decl. */ @@ -846,6 +854,12 @@ class ovl_iterator { return (TREE_CODE (ovl) == USING_DECL || (TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl))); } + /* Whether this using is being exported. */ + bool exporting_p () const + { + return OVL_EXPORT_P (get_using ()); + } + bool hidden_p () const { return TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl); @@ -961,8 +975,10 @@ public: operator vec_t *() const { return v; } vec_t ** operator& () { return &v; } - /* Breaks pointer/value consistency for convenience. */ - tree& operator[] (unsigned i) const { return (*v)[i]; } + /* Breaks pointer/value consistency for convenience. This takes ptrdiff_t + rather than unsigned to avoid ambiguity with the built-in operator[] + (bootstrap/91828). */ + tree& operator[] (ptrdiff_t i) const { return (*v)[i]; } ~releasing_vec() { release_tree_vector (v); } private: @@ -3161,6 +3177,13 @@ struct GTY(()) lang_decl { (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE)) \ ->u.base.friend_or_tls) +/* True of a TEMPLATE_DECL that is a template class friend. Such + decls are not pushed until instantiated (as they may depend on + parameters of the befriending class). DECL_CHAIN is the + befriending class. */ +#define DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P(NODE) \ + (DECL_LANG_FLAG_4 (TEMPLATE_DECL_CHECK (NODE))) + /* Nonzero if the thread-local variable was declared with __thread as opposed to thread_local. */ #define DECL_GNU_TLS_P(NODE) \ @@ -5399,10 +5422,6 @@ extern int function_depth; in structrual_comptypes. */ extern int comparing_specializations; -/* Nonzero if we are inside eq_specializations, which affects - resolving of typenames in structural_comptypes. */ -extern int comparing_typenames; - /* In parser.c. */ /* Nonzero if we are parsing an unevaluated operand: an operand to @@ -6863,6 +6882,103 @@ extern bool ctor_omit_inherited_parms (tree); extern tree locate_ctor (tree); extern tree implicitly_declare_fn (special_function_kind, tree, bool, tree, tree); +/* In module.cc */ +class module_state; /* Forward declare. */ +inline bool modules_p () { return flag_modules != 0; } + +/* The kind of module or part thereof that we're in. */ +enum module_kind_bits +{ + MK_MODULE = 1 << 0, /* This TU is a module. */ + MK_GLOBAL = 1 << 1, /* Entities are in the global module. */ + MK_INTERFACE = 1 << 2, /* This TU is an interface. */ + MK_PARTITION = 1 << 3, /* This TU is a partition. */ + MK_EXPORTING = 1 << 4, /* We are in an export region. */ +}; + +/* We do lots of bit-manipulation, so an unsigned is easier. */ +extern unsigned module_kind; + +/* MK_MODULE & MK_GLOBAL have the following combined meanings: + MODULE GLOBAL + 0 0 not a module + 0 1 GMF of named module (we've not yet seen module-decl) + 1 0 purview of named module + 1 1 header unit. */ + +inline bool module_purview_p () +{ return module_kind & MK_MODULE; } +inline bool global_purview_p () +{ return module_kind & MK_GLOBAL; } + +inline bool not_module_p () +{ return (module_kind & (MK_MODULE | MK_GLOBAL)) == 0; } +inline bool named_module_p () +{ /* This is a named module if exactly one of MODULE and GLOBAL is + set. */ + /* The divides are constant shifts! */ + return ((module_kind / MK_MODULE) ^ (module_kind / MK_GLOBAL)) & 1; +} +inline bool header_module_p () +{ return (module_kind & (MK_MODULE | MK_GLOBAL)) == (MK_MODULE | MK_GLOBAL); } +inline bool named_module_purview_p () +{ return (module_kind & (MK_MODULE | MK_GLOBAL)) == MK_MODULE; } +inline bool module_interface_p () +{ return module_kind & MK_INTERFACE; } +inline bool module_partition_p () +{ return module_kind & MK_PARTITION; } +inline bool module_has_cmi_p () +{ return module_kind & (MK_INTERFACE | MK_PARTITION); } + +/* We're currently exporting declarations. */ +inline bool module_exporting_p () +{ return module_kind & MK_EXPORTING; } + +extern module_state *get_module (tree name, module_state *parent = NULL, + bool partition = false); +extern bool module_may_redeclare (tree decl); + +extern int module_initializer_kind (); +extern void module_add_import_initializers (); + +/* Where the namespace-scope decl was originally declared. */ +extern void set_originating_module (tree, bool friend_p = false); +extern tree get_originating_module_decl (tree) ATTRIBUTE_PURE; +extern int get_originating_module (tree, bool for_mangle = false) ATTRIBUTE_PURE; +extern unsigned get_importing_module (tree, bool = false) ATTRIBUTE_PURE; + +/* Where current instance of the decl got declared/defined/instantiated. */ +extern void set_instantiating_module (tree); +extern void set_defining_module (tree); +extern void maybe_attach_decl (tree ctx, tree decl); + +extern void mangle_module (int m, bool include_partition); +extern void mangle_module_fini (); +extern void lazy_load_binding (unsigned mod, tree ns, tree id, + binding_slot *bslot); +extern void lazy_load_specializations (tree tmpl); +extern void lazy_load_members (tree decl); +extern bool lazy_specializations_p (unsigned, bool, bool); +extern module_state *preprocess_module (module_state *, location_t, + bool in_purview, + bool is_import, bool export_p, + cpp_reader *reader); +extern void preprocessed_module (cpp_reader *reader); +extern void import_module (module_state *, location_t, bool export_p, + tree attr, cpp_reader *); +extern void declare_module (module_state *, location_t, bool export_p, + tree attr, cpp_reader *); +extern void init_modules (cpp_reader *); +extern void fini_modules (); +extern void maybe_check_all_macros (cpp_reader *); +extern void finish_module_processing (cpp_reader *); +extern char const *module_name (unsigned, bool header_ok); +extern bitmap get_import_bitmap (); +extern bitmap module_visible_instantiation_path (bitmap *); +extern void module_begin_main_file (cpp_reader *, line_maps *, + const line_map_ordinary *); +extern void module_preprocess_options (cpp_reader *); +extern bool handle_module_option (unsigned opt, const char *arg, int value); /* In optimize.c */ extern bool maybe_clone_body (tree); @@ -7443,7 +7559,7 @@ extern bool is_local_temp (tree); extern tree build_aggr_init_expr (tree, tree); extern tree get_target_expr (tree); extern tree get_target_expr_sfinae (tree, tsubst_flags_t); -extern tree build_cplus_array_type (tree, tree, int is_dep = -1); +extern tree build_cplus_array_type (tree, tree); extern tree build_array_of_n_type (tree, int); extern bool array_of_runtime_bound_p (tree); extern bool vla_type_p (tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 1bc7b7e..46069cb 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1928,7 +1928,7 @@ static void clear_consteval_vfns (vec<tree> &consteval_vtables) { for (tree vtable : consteval_vtables) - for (constructor_elt &elt : *CONSTRUCTOR_ELTS (DECL_INITIAL (vtable))) + for (constructor_elt &elt : CONSTRUCTOR_ELTS (DECL_INITIAL (vtable))) { tree fn = cp_get_fndecl_from_callee (elt.value, /*fold*/false); if (fn && DECL_IMMEDIATE_FUNCTION_P (fn)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 103567c..cc3da15 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30611,9 +30611,6 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) { tree default_arg = TREE_PURPOSE (parm); tree parsed_arg; - vec<tree, va_gc> *insts; - tree copy; - unsigned ix; tree parmdecl = parms[i]; pushdecl (parmdecl); @@ -30633,8 +30630,7 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) TREE_PURPOSE (parm) = parsed_arg; /* Update any instantiations we've already created. */ - for (insts = DEFPARSE_INSTANTIATIONS (default_arg), ix = 0; - vec_safe_iterate (insts, ix, ©); ix++) + for (tree copy : DEFPARSE_INSTANTIATIONS (default_arg)) TREE_PURPOSE (copy) = parsed_arg; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3ca2813..2d3ab92 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -22,7 +22,9 @@ along with GCC; see the file COPYING3. If not see /* Known bugs or deficiencies include: all methods must be provided in header files; can't use a source - file that contains only the method templates and "just win". */ + file that contains only the method templates and "just win". + + Fixed by: C++20 modules. */ #include "config.h" #include "system.h" @@ -1702,19 +1704,16 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, return spec; } -/* Restricts tree and type comparisons. */ -int comparing_specializations; -int comparing_typenames; - /* Returns true iff two spec_entry nodes are equivalent. */ +int comparing_specializations; + bool spec_hasher::equal (spec_entry *e1, spec_entry *e2) { int equal; ++comparing_specializations; - ++comparing_typenames; equal = (e1->tmpl == e2->tmpl && comp_template_args (e1->args, e2->args)); if (equal && flag_concepts @@ -1730,7 +1729,6 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2) equal = equivalent_constraints (c1, c2); } --comparing_specializations; - --comparing_typenames; return equal; } @@ -6044,6 +6042,14 @@ push_template_decl (tree decl, bool is_friend) tmpl = NULL_TREE; } } + else if (is_friend) + { + /* Record this decl as belonging to the current class. It's + not chained onto anything else. */ + DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (tmpl) = true; + gcc_checking_assert (!DECL_CHAIN (tmpl)); + DECL_CHAIN (tmpl) = current_scope (); + } } else if (tmpl) /* The type may have been completed, or (erroneously) changed. */ @@ -8260,7 +8266,7 @@ convert_template_argument (tree parm, /* When determining whether an argument pack expansion is a template, look at the pattern. */ - if (TREE_CODE (arg) == TYPE_PACK_EXPANSION) + if (PACK_EXPANSION_P (arg)) arg = PACK_EXPANSION_PATTERN (arg); /* Deal with an injected-class-name used as a template template arg. */ @@ -11053,6 +11059,7 @@ tsubst_friend_function (tree decl, tree args) DECL_USE_TEMPLATE (new_friend) = 0; if (TREE_CODE (new_friend) == TEMPLATE_DECL) { + DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (new_friend) = false; DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0; DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (new_friend)) = DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (decl)); @@ -29006,6 +29013,12 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) return ptype; + /* Initializing one placeholder from another. */ + if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX + && is_auto (TREE_TYPE (init)) + && CLASS_PLACEHOLDER_TEMPLATE (TREE_TYPE (init)) == tmpl) + return cp_build_qualified_type (TREE_TYPE (init), cp_type_quals (ptype)); + /* Look through alias templates that just rename another template. */ tmpl = get_underlying_template (tmpl); if (!ctad_template_p (tmpl)) @@ -29022,10 +29035,6 @@ do_class_deduction (tree ptype, tree tmpl, tree init, "with %<-std=c++20%> or %<-std=gnu++20%>"); } - if (init && TREE_TYPE (init) == ptype) - /* Using the template parm as its own argument. */ - return ptype; - tree type = TREE_TYPE (tmpl); bool try_list_ctor = false; @@ -29273,7 +29282,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, /* We don't recurse here because we can't deduce from a nested initializer_list. */ if (CONSTRUCTOR_ELTS (init)) - for (constructor_elt &elt : *CONSTRUCTOR_ELTS (init)) + for (constructor_elt &elt : CONSTRUCTOR_ELTS (init)) elt.value = resolve_nondeduced_context (elt.value, complain); } else diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8d7df60..4e6bf9a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -998,7 +998,7 @@ build_min_array_type (tree elt_type, tree index_type) build_cplus_array_type. */ static void -set_array_type_canon (tree t, tree elt_type, tree index_type, bool dep) +set_array_type_canon (tree t, tree elt_type, tree index_type) { /* Set the canonical type for this new node. */ if (TYPE_STRUCTURAL_EQUALITY_P (elt_type) @@ -1009,33 +1009,30 @@ set_array_type_canon (tree t, tree elt_type, tree index_type, bool dep) TYPE_CANONICAL (t) = build_cplus_array_type (TYPE_CANONICAL (elt_type), index_type - ? TYPE_CANONICAL (index_type) : index_type, - dep); + ? TYPE_CANONICAL (index_type) : index_type); else TYPE_CANONICAL (t) = t; } /* Like build_array_type, but handle special C++ semantics: an array of a variant element type is a variant of the array of the main variant of - the element type. IS_DEPENDENT is -ve if we should determine the - dependency. Otherwise its bool value indicates dependency. */ + the element type. */ tree -build_cplus_array_type (tree elt_type, tree index_type, int dependent) +build_cplus_array_type (tree elt_type, tree index_type) { tree t; if (elt_type == error_mark_node || index_type == error_mark_node) return error_mark_node; - if (dependent < 0) - dependent = (uses_template_parms (elt_type) - || (index_type && uses_template_parms (index_type))); + bool dependent = (uses_template_parms (elt_type) + || (index_type && uses_template_parms (index_type))); if (elt_type != TYPE_MAIN_VARIANT (elt_type)) /* Start with an array of the TYPE_MAIN_VARIANT. */ t = build_cplus_array_type (TYPE_MAIN_VARIANT (elt_type), - index_type, dependent); + index_type); else if (dependent) { /* Since type_hash_canon calls layout_type, we need to use our own @@ -1065,20 +1062,13 @@ build_cplus_array_type (tree elt_type, tree index_type, int dependent) *e = t; /* Set the canonical type for this new node. */ - set_array_type_canon (t, elt_type, index_type, dependent); - - /* Mark it as dependent now, this saves time later. */ - TYPE_DEPENDENT_P_VALID (t) = true; - TYPE_DEPENDENT_P (t) = true; + set_array_type_canon (t, elt_type, index_type); } } else { bool typeless_storage = is_byte_access_type (elt_type); t = build_array_type (elt_type, index_type, typeless_storage); - - /* Mark as non-dependenty now, this will save time later. */ - TYPE_DEPENDENT_P_VALID (t) = true; } /* Now check whether we already have this array variant. */ @@ -1093,10 +1083,7 @@ build_cplus_array_type (tree elt_type, tree index_type, int dependent) if (!t) { t = build_min_array_type (elt_type, index_type); - /* Mark dependency now, this saves time later. */ - TYPE_DEPENDENT_P_VALID (t) = true; - TYPE_DEPENDENT_P (t) = dependent; - set_array_type_canon (t, elt_type, index_type, dependent); + set_array_type_canon (t, elt_type, index_type); if (!dependent) { layout_type (t); @@ -1332,10 +1319,7 @@ cp_build_qualified_type_real (tree type, if (!t) { - gcc_checking_assert (TYPE_DEPENDENT_P_VALID (type) - || !dependent_type_p (type)); - t = build_cplus_array_type (element_type, TYPE_DOMAIN (type), - TYPE_DEPENDENT_P (type)); + t = build_cplus_array_type (element_type, TYPE_DOMAIN (type)); /* Keep the typedef name. */ if (TYPE_NAME (t) != TYPE_NAME (type)) @@ -1571,9 +1555,7 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) case ARRAY_TYPE: type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); t0 = strip_typedefs (TYPE_DOMAIN (t), remove_attributes, flags); - gcc_checking_assert (TYPE_DEPENDENT_P_VALID (t) - || !dependent_type_p (t)); - result = build_cplus_array_type (type, t0, TYPE_DEPENDENT_P (t)); + result = build_cplus_array_type (type, t0); break; case FUNCTION_TYPE: case METHOD_TYPE: @@ -2272,10 +2254,11 @@ ovl_make (tree fn, tree next) return result; } -/* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN - is > 0, if FN is via a using declaration. USING_OR_HIDDEN is < 0, - if FN is hidden. (A decl cannot be both using and hidden.) We - keep the hidden decls first, but remaining ones are unordered. */ +/* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN is > + zero if this is a using-decl. It is > 1 if we're exporting the + using decl. USING_OR_HIDDEN is < 0, if FN is hidden. (A decl + cannot be both using and hidden.) We keep the hidden decls first, + but remaining ones are unordered. */ tree ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden) @@ -2299,7 +2282,11 @@ ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden) if (using_or_hidden < 0) OVL_HIDDEN_P (maybe_ovl) = true; if (using_or_hidden > 0) - OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true; + { + OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true; + if (using_or_hidden > 1) + OVL_EXPORT_P (maybe_ovl) = true; + } } else maybe_ovl = fn; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 6294a78..267b284 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1256,15 +1256,16 @@ structural_comptypes (tree t1, tree t2, int strict) gcc_assert (TYPE_P (t1) && TYPE_P (t2)); - /* TYPENAME_TYPEs should be resolved if the qualifying scope is the - current instantiation, and we don't care about typename - structural equality. The comparing_typenames check is after the - code check, in order to early-out the common case. */ - if (TREE_CODE (t1) == TYPENAME_TYPE && !comparing_typenames) - t1 = resolve_typename_type (t1, /*only_current_p=*/true); - - if (TREE_CODE (t2) == TYPENAME_TYPE && !comparing_typenames) - t2 = resolve_typename_type (t2, /*only_current_p=*/true); + if (!comparing_specializations) + { + /* TYPENAME_TYPEs should be resolved if the qualifying scope is the + current instantiation. */ + if (TREE_CODE (t1) == TYPENAME_TYPE) + t1 = resolve_typename_type (t1, /*only_current_p=*/true); + + if (TREE_CODE (t2) == TYPENAME_TYPE) + t2 = resolve_typename_type (t2, /*only_current_p=*/true); + } if (TYPE_PTRMEMFUNC_P (t1)) t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 195bb21..4357615 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3233,20 +3233,63 @@ this reason the attribute is not allowed on types to annotate indirect calls. @item malloc +@item malloc (@var{deallocator}) +@item malloc (@var{deallocator}, @var{ptr-index}) @cindex @code{malloc} function attribute @cindex functions that behave like malloc -This tells the compiler that a function is @code{malloc}-like, i.e., -that the pointer @var{P} returned by the function cannot alias any +Attribute @code{malloc} indicates that a function is @code{malloc}-like, +i.e., that the pointer @var{P} returned by the function cannot alias any other pointer valid when the function returns, and moreover no pointers to valid objects occur in any storage addressed by @var{P}. -Using this attribute can improve optimization. Compiler predicts -that a function with the attribute returns non-null in most cases. -Functions like -@code{malloc} and @code{calloc} have this property because they return -a pointer to uninitialized or zeroed-out storage. However, functions -like @code{realloc} do not have this property, as they can return a -pointer to storage containing pointers. +Independently, the form of the attribute with one or two arguments +associates @code{deallocator} as a suitable deallocation function for +pointers returned from the @code{malloc}-like function. @var{ptr-index} +denotes the positional argument to which when the pointer is passed in +calls to @code{deallocator} has the effect of deallocating it. + +Using the attribute with no arguments is designed to improve optimization. +The compiler predicts that a function with the attribute returns non-null +in most cases. Functions like @code{malloc} and @code{calloc} have this +property because they return a pointer to uninitialized or zeroed-out +storage. However, functions like @code{realloc} do not have this property, +as they may return pointers to storage containing pointers to existing +objects. + +Associating a function with a @var{deallocator} helps detect calls to +mismatched allocation and deallocation functions and diagnose them +under the control of options such as @option{-Wmismatched-dealloc}. +To indicate that an allocation function both satisifies the nonaliasing +property and has a deallocator associated with it, both the plain form +of the attribute and the one with the @var{deallocator} argument must +be used. + +For example, besides stating that the functions return pointers that do +not alias any others, the following declarations make the @code{fclose} +and @code{frepen} functions suitable deallocators for pointers returned +from all the functions that return them, and the @code{pclose} function +as the only other suitable deallocator besides @code{freopen} for pointers +returned from @code{popen}. The deallocator functions must declared +before they can be referenced in the attribute. + +@smallexample +int fclose (FILE*); +FILE* freopen (const char*, const char*, FILE*); +int pclose (FILE*); + +__attribute__ ((malloc, malloc (fclose), malloc (freopen, 3))) + FILE* fdopen (int); +__attribute__ ((malloc, malloc (fclose), malloc (freopen, 3))) + FILE* fopen (const char*, const char*); +__attribute__ ((malloc, malloc (fclose), malloc (freopen, 3))) + FILE* fmemopen(void *, size_t, const char *); +__attribute__ ((malloc, malloc (fclose), malloc (freopen, 3))) + FILE* freopen (const char*, const char*, FILE*); +__attribute__ ((malloc, malloc (pclose), malloc (freopen, 3))) + FILE* popen (const char*, const char*); +__attribute__ ((malloc, malloc (fclose), malloc (freopen, 3))) + FILE* tmpfile (void); +@end smallexample @item no_icf @cindex @code{no_icf} function attribute diff --git a/gcc/doc/implement-c.texi b/gcc/doc/implement-c.texi index 692297b..d7433ba 100644 --- a/gcc/doc/implement-c.texi +++ b/gcc/doc/implement-c.texi @@ -576,6 +576,11 @@ are of scalar types, the expression is interpreted by GCC as a read of the volatile object; in the other cases, the expression is only evaluated for its side effects. +When an object of an aggregate type, with the same size and alignment as a +scalar type @code{S}, is the subject of a volatile access by an assignment +expression or an atomic function, the access to it is performed as if the +object's declared type were @code{volatile S}. + @end itemize @node Declarators implementation diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 35cd3dc..671b297 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -242,7 +242,8 @@ in the following sections. -Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion @gol -Weffc++ -Wno-exceptions -Wextra-semi -Wno-inaccessible-base @gol -Wno-inherited-variadic-ctor -Wno-init-list-lifetime @gol --Wno-invalid-offsetof -Wno-literal-suffix -Wmismatched-tags @gol +-Wno-invalid-offsetof -Wno-literal-suffix @gol +-Wno-mismatched-new-delete -Wmismatched-tags @gol -Wmultiple-inheritance -Wnamespaces -Wnarrowing @gol -Wnoexcept -Wnoexcept-type -Wnon-virtual-dtor @gol -Wpessimizing-move -Wno-placement-new -Wplacement-new=@var{n} @gol @@ -452,7 +453,7 @@ Objective-C and Objective-C++ Dialects}. -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol -gas-loc-support -gno-as-loc-support @gol -gas-locview-support -gno-as-locview-support @gol --gcolumn-info -gno-column-info @gol +-gcolumn-info -gno-column-info -gdwarf32 -gdwarf64 @gol -gstatement-frontiers -gno-statement-frontiers @gol -gvariable-location-views -gno-variable-location-views @gol -ginternal-reset-location-views -gno-internal-reset-location-views @gol @@ -3859,6 +3860,40 @@ The warning is inactive inside a system header file, such as the STL, so one can still use the STL. One may also instantiate or specialize templates. +@item -Wno-mismatched-new-delete @r{(C++ and Objective-C++ only)} +@opindex Wmismatched-new-delete +@opindex Wno-mismatched-new-delete +Warn for mismatches between calls to @code{operator new} or @code{operator +delete} and the corresponding call to the allocation or deallocation function. +This includes invocations of C++ @code{operator delete} with pointers +returned from either mismatched forms of @code{operator new}, or from other +functions that allocate objects for which the @code{operator delete} isn't +a suitable deallocator, as well as calls to other deallocation functions +with pointers returned from @code{operator new} for which the deallocation +function isn't suitable. + +For example, the @code{delete} expression in the function below is diagnosed +because it doesn't match the array form of the @code{new} expression +the pointer argument was returned from. Similarly, the call to @code{free} +is also diagnosed. + +@smallexample +void f () +@{ + int *a = new int[n]; + delete a; // warning: mismatch in array forms of expressions + + char *p = new char[n]; + free (p); // warning: mismatch between new and free +@} +@end smallexample + +The related option @option{-Wmismatched-dealloc} diagnoses mismatches +involving allocation and deallocation functions other than @code{operator +new} and @code{operator delete}. + +@option{-Wmismatched-new-delete} is enabled by default. + @item -Wmismatched-tags @r{(C++ and Objective-C++ only)} @opindex Wmismatched-tags @opindex Wno-mismatched-tags @@ -6287,6 +6322,41 @@ Ignoring the warning can result in poorly optimized code. disable the warning, but this is not recommended and should be done only when non-existent profile data is justified. +@item -Wno-mismatched-dealloc +@opindex Wmismatched-dealloc +@opindex Wno-mismatched-dealloc + +Warn for calls to deallocation functions with pointer arguments returned +from from allocations functions for which the former isn't a suitable +deallocator. A pair of functions can be associated as matching allocators +and deallocators by use of attribute @code{malloc}. Unless disabled by +the @option{-fno-builtin} option the standard functions @code{calloc}, +@code{malloc}, @code{realloc}, and @code{free}, as well as the corresponding +forms of C++ @code{operator new} and @code{operator delete} are implicitly +associated as matching allocators and deallocators. In the following +example @code{mydealloc} is the deallocator for pointers returned from +@code{myalloc}. + +@smallexample +void mydealloc (void*); + +__attribute__ ((malloc (mydealloc, 1))) void* +myalloc (size_t); + +void f (void) +@{ + void *p = myalloc (32); + // @dots{}use p@dots{} + free (p); // warning: not a matching deallocator for myalloc + mydealloc (p); // ok +@} +@end smallexample + +In C++, the related option @option{-Wmismatched-new-delete} diagnoses +mismatches involving either @code{operator new} or @code{operator delete}. + +Option @option{-Wmismatched-dealloc} is enabled by default. + @item -Wmultistatement-macros @opindex Wmultistatement-macros @opindex Wno-multistatement-macros @@ -7778,8 +7848,23 @@ to @option{-Wframe-larger-than=}@samp{SIZE_MAX} or larger. @item -Wno-free-nonheap-object @opindex Wno-free-nonheap-object @opindex Wfree-nonheap-object -Do not warn when attempting to free an object that was not allocated -on the heap. +Warn when attempting to deallocate an object that was either not allocated +on the heap, or by using a pointer that was not returned from a prior call +to the corresponding allocation function. For example, because the call +to @code{stpcpy} returns a pointer to the terminating nul character and +not to the begginning of the object, the call to @code{free} below is +diagnosed. + +@smallexample +void f (char *p) +@{ + p = stpcpy (p, "abc"); + // ... + free (p); // warning +@} +@end smallexample + +@option{-Wfree-nonheap-object} is enabled by default. @item -Wstack-usage=@var{byte-size} @opindex Wstack-usage @@ -9569,6 +9654,18 @@ information as possible into a separate output file with the extension debug information. To be useful, this option requires a debugger capable of reading @file{.dwo} files. +@item -gdwarf32 +@itemx -gdwarf64 +@opindex gdwarf32 +@opindex gdwarf64 +If DWARF debugging information is enabled, the @option{-gdwarf32} selects +the 32-bit DWARF format and the @option{-gdwarf64} selects the 64-bit +DWARF format. The default is target specific, on most targets it is +@option{-gdwarf32} though. The 32-bit DWARF format is smaller, but +can't support more than 2GiB of debug information in any of the DWARF +debug information sections. The 64-bit DWARF format allows larger debug +information and might not be well supported by all consumers yet. + @item -gdescribe-dies @opindex gdescribe-dies Add description attributes to some DWARF DIEs that have no name attribute, @@ -12956,6 +13053,9 @@ growth limit is needed to avoid exponential explosion of code size. Thus for smaller units, the size is increased to @option{--param large-unit-insns} before applying @option{--param inline-unit-growth}. +@item lazy-modules +Maximum number of concurrently open C++ module files when lazy loading. + @item inline-unit-growth Specifies maximal overall growth of the compilation unit caused by inlining. For example, parameter value 20 limits unit growth to 1.2 times the original @@ -12967,6 +13067,9 @@ Specifies maximal overall growth of the compilation unit caused by interprocedural constant propagation. For example, parameter value 10 limits unit growth to 1.1 times the original size. +@item ipa-cp-large-unit-insns +The size of translation unit that IPA-CP pass considers large. + @item large-stack-frame The limit specifying large stack frames. While inlining the algorithm is trying to not grow past this limit too much. @@ -13021,19 +13124,19 @@ Deeper chains are still handled by late inlining. Probability (in percent) that C++ inline function with comdat visibility are shared across multiple compilation units. -@item ipa-modref-max-bases -@item ipa-modref-max-refs -@item ipa-modref-max-accesses +@item modref-max-bases +@item modref-max-refs +@item modref-max-accesses Specifies the maximal number of base pointers, referneces and accesses stored for a single function by mod/ref analysis. -@item ipa-modref-max-tests +@item modref-max-tests Specifies the maxmal number of tests alias oracle can perform to disambiguate memory locations using the mod/ref information. This parameter ought to be -bigger than @option{--param ipa-modref-max-bases} and @option{--param -ipa-modref-max-refs}. +bigger than @option{--param modref-max-bases} and @option{--param +modref-max-refs}. -@item ipa-modref-max-depth +@item modref-max-depth Specifies the maximum depth of DFS walk used by modref escape analysis. Setting to 0 disables the analysis completely. @@ -13881,6 +13984,12 @@ If the size of a local variable in bytes is smaller or equal to this number, directly poison (or unpoison) shadow memory instead of using run-time callbacks. +@item tsan-distinguish-volatile +Emit special instrumentation for accesses to volatiles. + +@item tsan-instrument-func-entry-exit +Emit instrumentation calls to __tsan_func_entry() and __tsan_func_exit(). + @item max-fsm-thread-path-insns Maximum number of instructions to copy when duplicating blocks on a finite state automaton jump thread path. @@ -13920,6 +14029,9 @@ we may be able to devirtualize speculatively. The maximum number of assertions to add along the default edge of a switch statement during VRP. +@item evrp-mode +Specifies the mode Early VRP should operate in. + @item unroll-jam-min-percent The minimum percentage of memory references that must be optimized away for the unroll-and-jam transformation to be considered profitable. @@ -14084,15 +14196,26 @@ Maximum number of VALUEs handled during a single find_base_term call. The maximum number of exploded nodes per program point within the analyzer, before terminating analysis of that point. +@item analyzer-max-constraints +The maximum number of constraints per state. + @item analyzer-min-snodes-for-call-summary The minimum number of supernodes within a function for the analyzer to consider summarizing its effects at call sites. +@item analyzer-max-enodes-for-full-dump +The maximum depth of exploded nodes that should appear in a dot dump +before switching to a less verbose format. + @item analyzer-max-recursion-depth The maximum number of times a callsite can appear in a call stack within the analyzer, before terminating analysis of a call that would recurse deeper. +@item analyzer-max-svalue-depth +The maximum depth of a symbolic value, before approximating +the value as unknown. + @item gimple-fe-computed-hot-bb-threshold The number of executions of a basic block which is considered hot. The parameter is used only in GIMPLE FE. diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index f507765..d9b855c 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8090,43 +8090,9 @@ need to override this if your target has special flags that might be set via @code{__attribute__}. @end deftypefn -@deftypefn {Target Hook} int TARGET_ASM_RECORD_GCC_SWITCHES (print_switch_type @var{type}, const char *@var{text}) +@deftypefn {Target Hook} void TARGET_ASM_RECORD_GCC_SWITCHES (const char *@var{}) Provides the target with the ability to record the gcc command line -switches that have been passed to the compiler, and options that are -enabled. The @var{type} argument specifies what is being recorded. -It can take the following values: - -@table @gcctabopt -@item SWITCH_TYPE_PASSED -@var{text} is a command line switch that has been set by the user. - -@item SWITCH_TYPE_ENABLED -@var{text} is an option which has been enabled. This might be as a -direct result of a command line switch, or because it is enabled by -default or because it has been enabled as a side effect of a different -command line switch. For example, the @option{-O2} switch enables -various different individual optimization passes. - -@item SWITCH_TYPE_DESCRIPTIVE -@var{text} is either NULL or some descriptive text which should be -ignored. If @var{text} is NULL then it is being used to warn the -target hook that either recording is starting or ending. The first -time @var{type} is SWITCH_TYPE_DESCRIPTIVE and @var{text} is NULL, the -warning is for start up and the second time the warning is for -wind down. This feature is to allow the target hook to make any -necessary preparations before it starts to record switches and to -perform any necessary tidying up after it has finished recording -switches. - -@item SWITCH_TYPE_LINE_START -This option can be ignored by this target hook. - -@item SWITCH_TYPE_LINE_END -This option can be ignored by this target hook. -@end table - -The hook's return value must be zero. Other return values may be -supported in the future. +switches provided as argument. By default this hook is set to NULL, but an example implementation is provided for ELF based targets. Called @var{elf_record_gcc_switches}, diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index c23a3ca..7b340ba 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -182,14 +182,14 @@ static GTY(()) section *debug_frame_section; bytes. However, the SGI/MIPS ABI uses an initial length which is equal to - DWARF_OFFSET_SIZE. It is defined (elsewhere) accordingly. */ + dwarf_offset_size. It is defined (elsewhere) accordingly. */ #ifndef DWARF_INITIAL_LENGTH_SIZE -#define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12) +#define DWARF_INITIAL_LENGTH_SIZE (dwarf_offset_size == 4 ? 4 : 12) #endif #ifndef DWARF_INITIAL_LENGTH_SIZE_STR -#define DWARF_INITIAL_LENGTH_SIZE_STR (DWARF_OFFSET_SIZE == 4 ? "-4" : "-12") +#define DWARF_INITIAL_LENGTH_SIZE_STR (dwarf_offset_size == 4 ? "-4" : "-12") #endif /* Round SIZE up to the nearest BOUNDARY. */ @@ -199,7 +199,7 @@ static GTY(()) section *debug_frame_section; /* CIE identifier. */ #if HOST_BITS_PER_WIDE_INT >= 64 #define DWARF_CIE_ID \ - (unsigned HOST_WIDE_INT) (DWARF_OFFSET_SIZE == 4 ? DW_CIE_ID : DW64_CIE_ID) + (unsigned HOST_WIDE_INT) (dwarf_offset_size == 4 ? DW_CIE_ID : DW64_CIE_ID) #else #define DWARF_CIE_ID DW_CIE_ID #endif @@ -287,8 +287,8 @@ static GTY(()) bool do_eh_frame = false; static unsigned int rnglist_idx; /* Data and reference forms for relocatable data. */ -#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4) -#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4) +#define DW_FORM_data (dwarf_offset_size == 8 ? DW_FORM_data8 : DW_FORM_data4) +#define DW_FORM_ref (dwarf_offset_size == 8 ? DW_FORM_ref8 : DW_FORM_ref4) #ifndef DEBUG_FRAME_SECTION #define DEBUG_FRAME_SECTION ".debug_frame" @@ -602,10 +602,10 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j); if (!XCOFF_DEBUGGING_INFO || for_eh) { - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4 && !for_eh) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value" " indicating 64-bit DWARF extension"); - dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1, + dw2_asm_output_delta (for_eh ? 4 : dwarf_offset_size, l2, l1, "FDE Length"); } ASM_OUTPUT_LABEL (asm_out_file, l1); @@ -613,7 +613,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, if (for_eh) dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset"); else - dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label, + dw2_asm_output_offset (dwarf_offset_size, section_start_label, debug_frame_section, "FDE CIE offset"); begin = second ? fde->dw_fde_second_begin : fde->dw_fde_begin; @@ -806,17 +806,17 @@ output_call_frame_info (int for_eh) ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh); if (!XCOFF_DEBUGGING_INFO || for_eh) { - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4 && !for_eh) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1, + dw2_asm_output_delta (for_eh ? 4 : dwarf_offset_size, l2, l1, "Length of Common Information Entry"); } ASM_OUTPUT_LABEL (asm_out_file, l1); /* Now that the CIE pointer is PC-relative for EH, use 0 to identify the CIE. */ - dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE), + dw2_asm_output_data ((for_eh ? 4 : dwarf_offset_size), (for_eh ? 0 : DWARF_CIE_ID), "CIE Identifier Tag"); @@ -1623,7 +1623,7 @@ loc_list_plus_const (dw_loc_list_ref list_head, poly_int64 offset) } #define DWARF_REF_SIZE \ - (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE) + (dwarf_version == 2 ? DWARF2_ADDR_SIZE : dwarf_offset_size) /* The number of bits that can be encoded by largest DW_FORM_dataN. In DWARF4 and earlier it is DW_FORM_data8 with 64 bits, in DWARF5 @@ -3229,33 +3229,33 @@ skeleton_chain_node; /* Fixed size portion of the DWARF compilation unit header. */ #define DWARF_COMPILE_UNIT_HEADER_SIZE \ - (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE \ + (DWARF_INITIAL_LENGTH_SIZE + dwarf_offset_size \ + (dwarf_version >= 5 ? 4 : 3)) /* Fixed size portion of the DWARF comdat type unit header. */ #define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \ (DWARF_COMPILE_UNIT_HEADER_SIZE \ - + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE) + + DWARF_TYPE_SIGNATURE_SIZE + dwarf_offset_size) /* Fixed size portion of the DWARF skeleton compilation unit header. */ #define DWARF_COMPILE_UNIT_SKELETON_HEADER_SIZE \ (DWARF_COMPILE_UNIT_HEADER_SIZE + (dwarf_version >= 5 ? 8 : 0)) /* Fixed size portion of public names info. */ -#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) +#define DWARF_PUBNAMES_HEADER_SIZE (2 * dwarf_offset_size + 2) /* Fixed size portion of the address range info. */ #define DWARF_ARANGES_HEADER_SIZE \ - (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \ + (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + dwarf_offset_size + 4, \ DWARF2_ADDR_SIZE * 2) \ - DWARF_INITIAL_LENGTH_SIZE) /* Size of padding portion in the address range info. It must be aligned to twice the pointer size. */ #define DWARF_ARANGES_PAD_SIZE \ - (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \ + (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + dwarf_offset_size + 4, \ DWARF2_ADDR_SIZE * 2) \ - - (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4)) + - (DWARF_INITIAL_LENGTH_SIZE + dwarf_offset_size + 4)) /* Use assembler line directives if available. */ #ifndef DWARF2_ASM_LINE_DEBUG_INFO @@ -4787,7 +4787,7 @@ find_string_form (struct indirect_string_node *node) /* If the string is shorter or equal to the size of the reference, it is always better to put it inline. */ - if (len <= DWARF_OFFSET_SIZE || node->refcount == 0) + if (len <= (unsigned) dwarf_offset_size || node->refcount == 0) return node->form = DW_FORM_string; /* If we cannot expect the linker to merge strings in .debug_str @@ -4795,7 +4795,7 @@ find_string_form (struct indirect_string_node *node) single module. */ if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET || ((debug_str_section->common.flags & SECTION_MERGE) == 0 - && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)) + && (len - dwarf_offset_size) * node->refcount <= len)) return node->form = DW_FORM_string; set_indirect_string (node); @@ -8892,7 +8892,7 @@ output_loclists_offsets (dw_die_ref die) dw_loc_list_ref l = AT_loc_list (a); if (l->offset_emitted) continue; - dw2_asm_output_delta (DWARF_OFFSET_SIZE, l->ll_symbol, + dw2_asm_output_delta (dwarf_offset_size, l->ll_symbol, loc_section_label, NULL); gcc_assert (l->hash == loc_list_idx); loc_list_idx++; @@ -9400,7 +9400,7 @@ size_of_die (dw_die_ref die) size += DWARF2_ADDR_SIZE; break; case dw_val_class_offset: - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_loc: { @@ -9421,10 +9421,10 @@ size_of_die (dw_die_ref die) size += size_of_uleb128 (AT_loc_list (a)->hash); } else - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_view_list: - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_range_list: if (value_format (a) == DW_FORM_rnglistx) @@ -9434,7 +9434,7 @@ size_of_die (dw_die_ref die) size += size_of_uleb128 (r->idx); } else - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_const: size += size_of_sleb128 (AT_int (a)); @@ -9508,13 +9508,13 @@ size_of_die (dw_die_ref die) else if (dwarf_version == 2) size += DWARF2_ADDR_SIZE; else - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; } else - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_fde_ref: - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_lbl_id: if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) @@ -9528,12 +9528,12 @@ size_of_die (dw_die_ref die) case dw_val_class_lineptr: case dw_val_class_macptr: case dw_val_class_loclistsptr: - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_str: form = AT_string_form (a); if (form == DW_FORM_strp || form == DW_FORM_line_strp) - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; else if (form == dwarf_FORM (DW_FORM_strx)) size += size_of_uleb128 (AT_index (a)); else @@ -9546,7 +9546,7 @@ size_of_die (dw_die_ref die) size += 8; break; case dw_val_class_vms_delta: - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; break; case dw_val_class_high_pc: size += DWARF2_ADDR_SIZE; @@ -9724,9 +9724,9 @@ size_of_pubnames (vec<pubname_entry, va_gc> *names) size = DWARF_PUBNAMES_HEADER_SIZE; FOR_EACH_VEC_ELT (*names, i, p) if (include_pubname_in_output (names, p)) - size += strlen (p->name) + DWARF_OFFSET_SIZE + 1 + space_for_flags; + size += strlen (p->name) + dwarf_offset_size + 1 + space_for_flags; - size += DWARF_OFFSET_SIZE; + size += dwarf_offset_size; return size; } @@ -9823,7 +9823,7 @@ value_format (dw_attr_node *a) /* FALLTHRU */ case dw_val_class_vms_delta: case dw_val_class_offset: - switch (DWARF_OFFSET_SIZE) + switch (dwarf_offset_size) { case 4: return DW_FORM_data4; @@ -10525,7 +10525,7 @@ output_range_list_offset (dw_attr_node *a) if (dwarf_version >= 5) { dw_ranges *r = &(*ranges_table)[a->dw_attr_val.v.val_offset]; - dw2_asm_output_offset (DWARF_OFFSET_SIZE, r->label, + dw2_asm_output_offset (dwarf_offset_size, r->label, debug_ranges_section, "%s", name); } else @@ -10533,7 +10533,7 @@ output_range_list_offset (dw_attr_node *a) char *p = strchr (ranges_section_label, '\0'); sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset * 2 * DWARF2_ADDR_SIZE); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label, + dw2_asm_output_offset (dwarf_offset_size, ranges_section_label, debug_ranges_section, "%s", name); *p = '\0'; } @@ -10545,7 +10545,7 @@ output_range_list_offset (dw_attr_node *a) dw2_asm_output_data_uleb128 (r->idx, "%s", name); } else - dw2_asm_output_data (DWARF_OFFSET_SIZE, + dw2_asm_output_data (dwarf_offset_size, a->dw_attr_val.v.val_offset * 2 * DWARF2_ADDR_SIZE, "%s (offset from %s)", name, ranges_section_label); } @@ -10559,7 +10559,7 @@ output_loc_list_offset (dw_attr_node *a) gcc_assert (sym); if (!dwarf_split_debug_info) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section, + dw2_asm_output_offset (dwarf_offset_size, sym, debug_loc_section, "%s", dwarf_attr_name (a->dw_attr)); else if (dwarf_version >= 5) { @@ -10569,7 +10569,7 @@ output_loc_list_offset (dw_attr_node *a) sym); } else - dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, + dw2_asm_output_delta (dwarf_offset_size, sym, loc_section_label, "%s", dwarf_attr_name (a->dw_attr)); } @@ -10582,10 +10582,10 @@ output_view_list_offset (dw_attr_node *a) gcc_assert (sym); if (dwarf_split_debug_info) - dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, + dw2_asm_output_delta (dwarf_offset_size, sym, loc_section_label, "%s", dwarf_attr_name (a->dw_attr)); else - dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section, + dw2_asm_output_offset (dwarf_offset_size, sym, debug_loc_section, "%s", dwarf_attr_name (a->dw_attr)); } @@ -10663,7 +10663,7 @@ output_die (dw_die_ref die) break; case dw_val_class_offset: - dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset, + dw2_asm_output_data (dwarf_offset_size, a->dw_attr_val.v.val_offset, "%s", name); break; @@ -10857,7 +10857,7 @@ output_die (dw_die_ref die) if (dwarf_version == 2) size = DWARF2_ADDR_SIZE; else - size = DWARF_OFFSET_SIZE; + size = dwarf_offset_size; /* ??? We cannot unconditionally output die_offset if non-zero - others might create references to those DIEs via symbols. @@ -10877,7 +10877,7 @@ output_die (dw_die_ref die) else { gcc_assert (AT_ref (a)->die_offset); - dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset, + dw2_asm_output_data (dwarf_offset_size, AT_ref (a)->die_offset, "%s", name); } break; @@ -10888,18 +10888,18 @@ output_die (dw_die_ref die) ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL, a->dw_attr_val.v.val_fde_index * 2); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section, + dw2_asm_output_offset (dwarf_offset_size, l1, debug_frame_section, "%s", name); } break; case dw_val_class_vms_delta: #ifdef ASM_OUTPUT_DWARF_VMS_DELTA - dw2_asm_output_vms_delta (DWARF_OFFSET_SIZE, + dw2_asm_output_vms_delta (dwarf_offset_size, AT_vms_delta2 (a), AT_vms_delta1 (a), "%s", name); #else - dw2_asm_output_delta (DWARF_OFFSET_SIZE, + dw2_asm_output_delta (dwarf_offset_size, AT_vms_delta2 (a), AT_vms_delta1 (a), "%s", name); #endif @@ -10910,28 +10910,28 @@ output_die (dw_die_ref die) break; case dw_val_class_lineptr: - dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a), + dw2_asm_output_offset (dwarf_offset_size, AT_lbl (a), debug_line_section, "%s", name); break; case dw_val_class_macptr: - dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a), + dw2_asm_output_offset (dwarf_offset_size, AT_lbl (a), debug_macinfo_section, "%s", name); break; case dw_val_class_loclistsptr: - dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a), + dw2_asm_output_offset (dwarf_offset_size, AT_lbl (a), debug_loc_section, "%s", name); break; case dw_val_class_str: if (a->dw_attr_val.v.val_str->form == DW_FORM_strp) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, + dw2_asm_output_offset (dwarf_offset_size, a->dw_attr_val.v.val_str->label, debug_str_section, "%s: \"%s\"", name, AT_string (a)); else if (a->dw_attr_val.v.val_str->form == DW_FORM_line_strp) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, + dw2_asm_output_offset (dwarf_offset_size, a->dw_attr_val.v.val_str->label, debug_line_str_section, "%s: \"%s\"", name, AT_string (a)); @@ -11048,10 +11048,10 @@ output_compilation_unit_header (enum dwarf_unit_type ut) { if (!XCOFF_DEBUGGING_INFO) { - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, + dw2_asm_output_data (dwarf_offset_size, next_die_offset - DWARF_INITIAL_LENGTH_SIZE, "Length of Compilation Unit Info"); } @@ -11071,7 +11071,7 @@ output_compilation_unit_header (enum dwarf_unit_type ut) dw2_asm_output_data (1, ut, "%s", name); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); } - dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label, + dw2_asm_output_offset (dwarf_offset_size, abbrev_section_label, debug_abbrev_section, "Offset Into Abbrev. Section"); if (dwarf_version < 5) @@ -11261,12 +11261,12 @@ output_skeleton_debug_sections (dw_die_ref comp_unit, /* Produce the skeleton compilation-unit header. This one differs enough from a normal CU header that it's better not to call output_compilation_unit header. */ - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit " "DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, + dw2_asm_output_data (dwarf_offset_size, DWARF_COMPILE_UNIT_SKELETON_HEADER_SIZE - DWARF_INITIAL_LENGTH_SIZE + size_of_die (comp_unit), @@ -11277,7 +11277,7 @@ output_skeleton_debug_sections (dw_die_ref comp_unit, dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton"); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); } - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label, + dw2_asm_output_offset (dwarf_offset_size, debug_skeleton_abbrev_section_label, debug_skeleton_abbrev_section, "Offset Into Abbrev. Section"); if (dwarf_version < 5) @@ -11362,7 +11362,7 @@ output_comdat_type_unit (comdat_type_node *node, output_compilation_unit_header (dwarf_split_debug_info ? DW_UT_split_type : DW_UT_type); output_signature (node->signature, "Type Signature"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset, + dw2_asm_output_data (dwarf_offset_size, node->type_die->die_offset, "Offset to Type DIE"); output_die (node->root_die); @@ -11491,7 +11491,7 @@ output_pubname (dw_offset die_offset, pubname_entry *entry) dw_die_ref die = entry->die; int is_static = get_AT_flag (die, DW_AT_external) ? 0 : 1; - dw2_asm_output_data (DWARF_OFFSET_SIZE, die_offset, "DIE offset"); + dw2_asm_output_data (dwarf_offset_size, die_offset, "DIE offset"); if (debug_generate_pub_sections == 2) { @@ -11565,10 +11565,10 @@ output_pubnames (vec<pubname_entry, va_gc> *names) if (!XCOFF_DEBUGGING_INFO) { - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length, + dw2_asm_output_data (dwarf_offset_size, pubnames_length, "Pub Info Length"); } @@ -11576,14 +11576,14 @@ output_pubnames (vec<pubname_entry, va_gc> *names) dw2_asm_output_data (2, 2, "DWARF pubnames/pubtypes version"); if (dwarf_split_debug_info) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, + dw2_asm_output_offset (dwarf_offset_size, debug_skeleton_info_section_label, debug_skeleton_info_section, "Offset of Compilation Unit Info"); else - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + dw2_asm_output_offset (dwarf_offset_size, debug_info_section_label, debug_info_section, "Offset of Compilation Unit Info"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset, + dw2_asm_output_data (dwarf_offset_size, next_die_offset, "Compilation Unit Length"); FOR_EACH_VEC_ELT (*names, i, pub) @@ -11614,7 +11614,7 @@ output_pubnames (vec<pubname_entry, va_gc> *names) } } - dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL); + dw2_asm_output_data (dwarf_offset_size, 0, NULL); } /* Output public names and types tables if necessary. */ @@ -11647,21 +11647,21 @@ output_aranges (void) if (!XCOFF_DEBUGGING_INFO) { - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length, + dw2_asm_output_data (dwarf_offset_size, aranges_length, "Length of Address Ranges Info"); } /* Version number for aranges is still 2, even up to DWARF5. */ dw2_asm_output_data (2, 2, "DWARF aranges version"); if (dwarf_split_debug_info) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, + dw2_asm_output_offset (dwarf_offset_size, debug_skeleton_info_section_label, debug_skeleton_info_section, "Offset of Compilation Unit Info"); else - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + dw2_asm_output_offset (dwarf_offset_size, debug_info_section_label, debug_info_section, "Offset of Compilation Unit Info"); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address"); @@ -11936,11 +11936,11 @@ output_rnglists (unsigned generation) 2 + generation * 4); ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_RANGES_SECTION_LABEL, 3 + generation * 4); - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating " "64-bit DWARF extension"); - dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, + dw2_asm_output_delta (dwarf_offset_size, l2, l1, "Length of Range Lists"); ASM_OUTPUT_LABEL (asm_out_file, l1); output_dwarf_version (); @@ -11959,7 +11959,7 @@ output_rnglists (unsigned generation) ASM_OUTPUT_LABEL (asm_out_file, ranges_base_label); FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) if (r->label) - dw2_asm_output_delta (DWARF_OFFSET_SIZE, r->label, + dw2_asm_output_delta (dwarf_offset_size, r->label, ranges_base_label, NULL); } @@ -12219,7 +12219,7 @@ output_line_string (enum dwarf_form form, const char *str, node = find_AT_string_in_table (str, debug_line_str_hash); set_indirect_string (node); node->form = form; - dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + dw2_asm_output_offset (dwarf_offset_size, node->label, debug_line_str_section, "%s: %#x: \"%s\"", entry_kind, 0, node->str); break; @@ -12728,10 +12728,10 @@ output_line_info (bool prologue_only) if (!XCOFF_DEBUGGING_INFO) { - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, + dw2_asm_output_delta (dwarf_offset_size, l2, l1, "Length of Source Line Info"); } @@ -12743,7 +12743,7 @@ output_line_info (bool prologue_only) dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); dw2_asm_output_data (1, 0, "Segment Size"); } - dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); + dw2_asm_output_delta (dwarf_offset_size, p2, p1, "Prolog Length"); ASM_OUTPUT_LABEL (asm_out_file, p1); /* Define the architecture-dependent minimum instruction length (in bytes). @@ -24438,115 +24438,6 @@ gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die) static char *producer_string; -/* Return a heap allocated producer string including command line options - if -grecord-gcc-switches. */ - -static char * -gen_producer_string (void) -{ - size_t j; - auto_vec<const char *> switches; - const char *language_string = lang_hooks.name; - char *producer, *tail; - const char *p; - size_t len = dwarf_record_gcc_switches ? 0 : 3; - size_t plen = strlen (language_string) + 1 + strlen (version_string); - - for (j = 1; dwarf_record_gcc_switches && j < save_decoded_options_count; j++) - switch (save_decoded_options[j].opt_index) - { - case OPT_o: - case OPT_d: - case OPT_dumpbase: - case OPT_dumpbase_ext: - case OPT_dumpdir: - case OPT_quiet: - case OPT_version: - case OPT_v: - case OPT_w: - case OPT_L: - case OPT_D: - case OPT_I: - case OPT_U: - case OPT_SPECIAL_unknown: - case OPT_SPECIAL_ignore: - case OPT_SPECIAL_warn_removed: - case OPT_SPECIAL_program_name: - case OPT_SPECIAL_input_file: - case OPT_grecord_gcc_switches: - case OPT__output_pch_: - case OPT_fdiagnostics_show_location_: - case OPT_fdiagnostics_show_option: - case OPT_fdiagnostics_show_caret: - case OPT_fdiagnostics_show_labels: - case OPT_fdiagnostics_show_line_numbers: - case OPT_fdiagnostics_color_: - case OPT_fdiagnostics_format_: - case OPT_fverbose_asm: - case OPT____: - case OPT__sysroot_: - case OPT_nostdinc: - case OPT_nostdinc__: - case OPT_fpreprocessed: - case OPT_fltrans_output_list_: - case OPT_fresolution_: - case OPT_fdebug_prefix_map_: - case OPT_fmacro_prefix_map_: - case OPT_ffile_prefix_map_: - case OPT_fcompare_debug: - case OPT_fchecking: - case OPT_fchecking_: - /* Ignore these. */ - continue; - case OPT_flto_: - { - const char *lto_canonical = "-flto"; - switches.safe_push (lto_canonical); - len += strlen (lto_canonical) + 1; - break; - } - default: - if (cl_options[save_decoded_options[j].opt_index].flags - & CL_NO_DWARF_RECORD) - continue; - gcc_checking_assert (save_decoded_options[j].canonical_option[0][0] - == '-'); - switch (save_decoded_options[j].canonical_option[0][1]) - { - case 'M': - case 'i': - case 'W': - continue; - case 'f': - if (strncmp (save_decoded_options[j].canonical_option[0] + 2, - "dump", 4) == 0) - continue; - break; - default: - break; - } - switches.safe_push (save_decoded_options[j].orig_option_with_args_text); - len += strlen (save_decoded_options[j].orig_option_with_args_text) + 1; - break; - } - - producer = XNEWVEC (char, plen + 1 + len + 1); - tail = producer; - sprintf (tail, "%s %s", language_string, version_string); - tail += plen; - - FOR_EACH_VEC_ELT (switches, j, p) - { - len = strlen (p); - *tail = ' '; - memcpy (tail + 1, p, len); - tail += len + 1; - } - - *tail = '\0'; - return producer; -} - /* Given a C and/or C++ language/version string return the "highest". C++ is assumed to be "higher" than C in this case. Used for merging LTO translation unit languages. */ @@ -28317,7 +28208,7 @@ output_macinfo_op (macinfo_entry *ref) case DW_MACINFO_undef: len = strlen (ref->info) + 1; if (!dwarf_strict - && len > DWARF_OFFSET_SIZE + && len > (size_t) dwarf_offset_size && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET && (debug_str_section->common.flags & SECTION_MERGE) != 0) { @@ -28358,7 +28249,7 @@ output_macinfo_op (macinfo_entry *ref) dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", (unsigned long) ref->lineno); if (node->form == DW_FORM_strp) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + dw2_asm_output_offset (dwarf_offset_size, node->label, debug_str_section, "The macro: \"%s\"", ref->info); else @@ -28370,7 +28261,7 @@ output_macinfo_op (macinfo_entry *ref) ASM_GENERATE_INTERNAL_LABEL (label, DEBUG_MACRO_SECTION_LABEL, ref->lineno + macinfo_label_base); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL); + dw2_asm_output_offset (dwarf_offset_size, label, NULL, NULL); break; default: fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n", @@ -28454,7 +28345,7 @@ optimize_macinfo_range (unsigned int idx, vec<macinfo_entry, va_gc> *files, /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum> */ grp_name = XALLOCAVEC (char, 4 + encoded_filename_len + linebuf_len + 1 + 16 * 2 + 1); - memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4); + memcpy (grp_name, dwarf_offset_size == 4 ? "wm4." : "wm8.", 4); tail = grp_name + 4; if (encoded_filename_len) { @@ -28525,7 +28416,7 @@ save_macinfo_strings (void) case DW_MACINFO_undef: len = strlen (ref->info) + 1; if (!dwarf_strict - && len > DWARF_OFFSET_SIZE + && len > (unsigned) dwarf_offset_size && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET && (debug_str_section->common.flags & SECTION_MERGE) != 0) set_indirect_string (find_AT_string (ref->info)); @@ -28578,11 +28469,11 @@ output_macinfo (const char *debug_line_label, bool early_lto_debug) { dw2_asm_output_data (2, dwarf_version >= 5 ? 5 : 4, "DWARF macro version number"); - if (DWARF_OFFSET_SIZE == 8) + if (dwarf_offset_size == 8) dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present"); else dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_label, + dw2_asm_output_offset (dwarf_offset_size, debug_line_label, debug_line_section, NULL); } @@ -28671,7 +28562,7 @@ output_macinfo (const char *debug_line_label, bool early_lto_debug) ref->info = NULL; dw2_asm_output_data (2, dwarf_version >= 5 ? 5 : 4, "DWARF macro version number"); - if (DWARF_OFFSET_SIZE == 8) + if (dwarf_offset_size == 8) dw2_asm_output_data (1, 1, "Flags: 64-bit"); else dw2_asm_output_data (1, 0, "Flags: 32-bit"); @@ -29008,7 +28899,7 @@ output_index_string_offset (indirect_string_node **h, unsigned int *offset) /* Assert that this node has been assigned an index. */ gcc_assert (node->index != NO_INDEX_ASSIGNED && node->index != NOT_INDEXED); - dw2_asm_output_data (DWARF_OFFSET_SIZE, *offset, + dw2_asm_output_data (dwarf_offset_size, *offset, "indexed string 0x%x: %s", node->index, node->str); *offset += strlen (node->str) + 1; } @@ -29102,11 +28993,11 @@ output_indirect_strings (void) debug_str_hash->traverse_noresize <unsigned int *, count_index_strings> (&last_idx); - str_offsets_length = last_idx * DWARF_OFFSET_SIZE + 4; - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + str_offsets_length = last_idx * dwarf_offset_size + 4; + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Escape value for 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, str_offsets_length, + dw2_asm_output_data (dwarf_offset_size, str_offsets_length, "Length of string offsets unit"); dw2_asm_output_data (2, 5, "DWARF string offsets version"); dw2_asm_output_data (2, 0, "Header zero padding"); @@ -29196,10 +29087,10 @@ output_addr_table (void) <unsigned int *, count_index_addrs> (&last_idx); addrs_length = last_idx * DWARF2_ADDR_SIZE + 4; - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Escape value for 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, addrs_length, + dw2_asm_output_data (dwarf_offset_size, addrs_length, "Length of Address Unit"); dw2_asm_output_data (2, 5, "DWARF addr version"); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address"); @@ -31758,11 +31649,11 @@ dwarf2out_finish (const char *filename) { ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_LOC_SECTION_LABEL, 2); ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_LOC_SECTION_LABEL, 3); - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating " "64-bit DWARF extension"); - dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, + dw2_asm_output_delta (dwarf_offset_size, l2, l1, "Length of Location Lists"); ASM_OUTPUT_LABEL (asm_out_file, l1); output_dwarf_version (); @@ -32157,7 +32048,14 @@ dwarf2out_early_finish (const char *filename) header compilation, so always fill it with empty string initially and overwrite only here. */ dw_attr_node *producer = get_AT (comp_unit_die (), DW_AT_producer); - producer_string = gen_producer_string (); + + if (dwarf_record_gcc_switches) + producer_string = gen_producer_string (lang_hooks.name, + save_decoded_options, + save_decoded_options_count); + else + producer_string = concat (lang_hooks.name, " ", version_string, NULL); + producer->dw_attr_val.v.val_str->refcount--; producer->dw_attr_val.v.val_str = find_AT_string (producer_string); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index e77d74e..1241b13 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8104,11 +8104,12 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, { if (valueinit == -1) { - tree zero = build_constructor (TREE_TYPE (type), NULL); + tree zero = build_zero_cst (TREE_TYPE (type)); r = native_encode_initializer (zero, ptr + curpos, fieldsize, 0, mask + curpos); - ggc_free (zero); + if (TREE_CODE (zero) == CONSTRUCTOR) + ggc_free (zero); if (!r) return 0; valueinit = curpos; @@ -8255,8 +8256,9 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, { cnt--; field = fld; - val = build_constructor (TREE_TYPE (fld), NULL); - to_free = val; + val = build_zero_cst (TREE_TYPE (fld)); + if (TREE_CODE (val) == CONSTRUCTOR) + to_free = val; } } diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index a8e8bbb..1826640 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2020-12-03 Harald Anlauf <anlauf@gmx.de> + + PR fortran/95342 + * decl.c (gfc_match_function_decl): Avoid NULL pointer dereference. + (gfc_match_subroutine): Likewise. + 2020-11-30 Tobias Burnus <tobias@codesourcery.com> PR fortran/98011 diff --git a/gcc/gimple.c b/gcc/gimple.c index e8246b7..bb13458 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1514,11 +1514,12 @@ gimple_call_fnspec (const gcall *stmt) such operator, then we can treat it as free. */ if (fndecl && DECL_IS_OPERATOR_DELETE_P (fndecl) + && DECL_IS_REPLACEABLE_OPERATOR (fndecl) && gimple_call_from_new_or_delete (stmt)) return ".co "; /* Similarly operator new can be treated as malloc. */ if (fndecl - && DECL_IS_OPERATOR_NEW_P (fndecl) + && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl) && gimple_call_from_new_or_delete (stmt)) return "mC"; return ""; diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index cd1a396..019aafd 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -b3a0b068f7fa2d65ba781271b2c0479d103b7d7b +342e5f0b349553a69d7c99a18162ae2a1e6e5775 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c index 82acc6a..7adc4b6 100644 --- a/gcc/ipa-sra.c +++ b/gcc/ipa-sra.c @@ -1480,7 +1480,7 @@ verify_access_tree_1 (gensum_param_access *access, HOST_WIDE_INT parent_offset, { while (access) { - gcc_assert (access->offset >= 0 && access->size > 0); + gcc_assert (access->offset >= 0 && access->size >= 0); if (parent_size != 0) { @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "spellcheck.h" #include "opt-suggestions.h" #include "diagnostic-color.h" +#include "version.h" #include "selftest.h" static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff); @@ -3266,6 +3267,124 @@ get_option_url (diagnostic_context *, int option_index) return NULL; } +/* Return a heap allocated producer with command line options. */ + +char * +gen_command_line_string (cl_decoded_option *options, + unsigned int options_count) +{ + auto_vec<const char *> switches; + char *options_string, *tail; + const char *p; + size_t len = 0; + + for (unsigned i = 0; i < options_count; i++) + switch (options[i].opt_index) + { + case OPT_o: + case OPT_d: + case OPT_dumpbase: + case OPT_dumpdir: + case OPT_quiet: + case OPT_version: + case OPT_v: + case OPT_w: + case OPT_L: + case OPT_D: + case OPT_I: + case OPT_U: + case OPT_SPECIAL_unknown: + case OPT_SPECIAL_ignore: + case OPT_SPECIAL_warn_removed: + case OPT_SPECIAL_program_name: + case OPT_SPECIAL_input_file: + case OPT_grecord_gcc_switches: + case OPT_frecord_gcc_switches: + case OPT__output_pch_: + case OPT_fdiagnostics_show_location_: + case OPT_fdiagnostics_show_option: + case OPT_fdiagnostics_show_caret: + case OPT_fdiagnostics_show_labels: + case OPT_fdiagnostics_show_line_numbers: + case OPT_fdiagnostics_color_: + case OPT_fdiagnostics_format_: + case OPT_fverbose_asm: + case OPT____: + case OPT__sysroot_: + case OPT_nostdinc: + case OPT_nostdinc__: + case OPT_fpreprocessed: + case OPT_fltrans_output_list_: + case OPT_fresolution_: + case OPT_fdebug_prefix_map_: + case OPT_fmacro_prefix_map_: + case OPT_ffile_prefix_map_: + case OPT_fcompare_debug: + case OPT_fchecking: + case OPT_fchecking_: + /* Ignore these. */ + continue; + case OPT_flto_: + { + const char *lto_canonical = "-flto"; + switches.safe_push (lto_canonical); + len += strlen (lto_canonical) + 1; + break; + } + default: + if (cl_options[options[i].opt_index].flags + & CL_NO_DWARF_RECORD) + continue; + gcc_checking_assert (options[i].canonical_option[0][0] == '-'); + switch (options[i].canonical_option[0][1]) + { + case 'M': + case 'i': + case 'W': + continue; + case 'f': + if (strncmp (options[i].canonical_option[0] + 2, + "dump", 4) == 0) + continue; + break; + default: + break; + } + switches.safe_push (options[i].orig_option_with_args_text); + len += strlen (options[i].orig_option_with_args_text) + 1; + break; + } + + options_string = XNEWVEC (char, len + 1); + tail = options_string; + + unsigned i; + FOR_EACH_VEC_ELT (switches, i, p) + { + len = strlen (p); + memcpy (tail, p, len); + tail += len; + if (i != switches.length () - 1) + { + *tail = ' '; + ++tail; + } + } + + *tail = '\0'; + return options_string; +} + +/* Return a heap allocated producer string including command line options. */ + +char * +gen_producer_string (const char *language_string, cl_decoded_option *options, + unsigned int options_count) +{ + return concat (language_string, " ", version_string, " ", + gen_command_line_string (options, options_count), NULL); +} + #if CHECKING_P namespace selftest { @@ -482,6 +482,12 @@ extern void parse_options_from_collect_gcc_options (const char *, obstack *, extern void prepend_xassembler_to_collect_as_options (const char *, obstack *); +extern char *gen_command_line_string (cl_decoded_option *options, + unsigned int options_count); +extern char *gen_producer_string (const char *language_string, + cl_decoded_option *options, + unsigned int options_count); + /* Set OPTION in OPTS to VALUE if the option is not set in OPTS_SET. */ #define SET_OPTION_IF_UNSET(OPTS, OPTS_SET, OPTION, VALUE) \ diff --git a/gcc/target.def b/gcc/target.def index a0ea853..acdc694 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -757,41 +757,7 @@ directive to annotate @var{symbol} as used. The Darwin target uses the\n\ DEFHOOK (record_gcc_switches, "Provides the target with the ability to record the gcc command line\n\ -switches that have been passed to the compiler, and options that are\n\ -enabled. The @var{type} argument specifies what is being recorded.\n\ -It can take the following values:\n\ -\n\ -@table @gcctabopt\n\ -@item SWITCH_TYPE_PASSED\n\ -@var{text} is a command line switch that has been set by the user.\n\ -\n\ -@item SWITCH_TYPE_ENABLED\n\ -@var{text} is an option which has been enabled. This might be as a\n\ -direct result of a command line switch, or because it is enabled by\n\ -default or because it has been enabled as a side effect of a different\n\ -command line switch. For example, the @option{-O2} switch enables\n\ -various different individual optimization passes.\n\ -\n\ -@item SWITCH_TYPE_DESCRIPTIVE\n\ -@var{text} is either NULL or some descriptive text which should be\n\ -ignored. If @var{text} is NULL then it is being used to warn the\n\ -target hook that either recording is starting or ending. The first\n\ -time @var{type} is SWITCH_TYPE_DESCRIPTIVE and @var{text} is NULL, the\n\ -warning is for start up and the second time the warning is for\n\ -wind down. This feature is to allow the target hook to make any\n\ -necessary preparations before it starts to record switches and to\n\ -perform any necessary tidying up after it has finished recording\n\ -switches.\n\ -\n\ -@item SWITCH_TYPE_LINE_START\n\ -This option can be ignored by this target hook.\n\ -\n\ -@item SWITCH_TYPE_LINE_END\n\ -This option can be ignored by this target hook.\n\ -@end table\n\ -\n\ -The hook's return value must be zero. Other return values may be\n\ -supported in the future.\n\ +switches provided as argument.\n\ \n\ By default this hook is set to NULL, but an example implementation is\n\ provided for ELF based targets. Called @var{elf_record_gcc_switches},\n\ @@ -799,7 +765,7 @@ it records the switches as ASCII text inside a new, string mergeable\n\ section in the assembler output file. The name of the new section is\n\ provided by the @code{TARGET_ASM_RECORD_GCC_SWITCHES_SECTION} target\n\ hook.", - int, (print_switch_type type, const char *text), + void, (const char *), NULL) /* The name of the section that the example ELF implementation of diff --git a/gcc/target.h b/gcc/target.h index 440cd25..9601880 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -68,16 +68,6 @@ union cumulative_args_t { void *p; }; #endif /* !CHECKING_P */ -/* Types used by the record_gcc_switches() target function. */ -enum print_switch_type -{ - SWITCH_TYPE_PASSED, /* A switch passed on the command line. */ - SWITCH_TYPE_ENABLED, /* An option that is currently enabled. */ - SWITCH_TYPE_DESCRIPTIVE, /* Descriptive text, not a switch or option. */ - SWITCH_TYPE_LINE_START, /* Please emit any necessary text at the start of a line. */ - SWITCH_TYPE_LINE_END /* Please emit a line terminator. */ -}; - /* Types of memory operation understood by the "by_pieces" infrastructure. Used by the TARGET_USE_BY_PIECES_INFRASTRUCTURE_P target hook and internally by the functions in expr.c. */ @@ -96,10 +86,8 @@ extern unsigned HOST_WIDE_INT by_pieces_ninsns (unsigned HOST_WIDE_INT, unsigned int, by_pieces_operation); -typedef int (* print_switch_fn_type) (print_switch_type, const char *); - /* An example implementation for ELF targets. Defined in varasm.c */ -extern int elf_record_gcc_switches (print_switch_type type, const char *); +extern void elf_record_gcc_switches (const char *); /* Some places still assume that all pointer or address modes are the standard Pmode and ptr_mode. These optimizations become invalid if diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3339d70..0e91a06 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,148 @@ +2020-12-03 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp2a/concepts-nodiscard1.C: XFAIL. + +2020-12-03 Martin Sebor <msebor@redhat.com> + + PR c++/90629 + PR middle-end/94527 + * g++.dg/asan/asan_test.cc: Fix a bug. + * g++.dg/warn/delete-array-1.C: Add expected warning. + * g++.old-deja/g++.other/delete2.C: Add expected warning. + * g++.dg/warn/Wfree-nonheap-object-2.C: New test. + * g++.dg/warn/Wfree-nonheap-object.C: New test. + * g++.dg/warn/Wmismatched-new-delete.C: New test. + * g++.dg/warn/Wmismatched-dealloc-2.C: New test. + * g++.dg/warn/Wmismatched-dealloc.C: New test. + * gcc.dg/Wmismatched-dealloc.c: New test. + * gcc.dg/analyzer/malloc-1.c: Prune out expected warning. + * gcc.dg/attr-malloc.c: New test. + * gcc.dg/free-1.c: Adjust text of expected warning. + * gcc.dg/free-2.c: Same. + * gcc.dg/torture/pr71816.c: Prune out expected warning. + * gcc.dg/tree-ssa/pr19831-2.c: Add an expected warning. + * gcc.dg/Wfree-nonheap-object-2.c: New test. + * gcc.dg/Wfree-nonheap-object-3.c: New test. + * gcc.dg/Wfree-nonheap-object.c: New test. + * g++.dg/warn/Wfree-nonheap-object.s: New file. + +2020-12-03 Harald Anlauf <anlauf@gmx.de> + + PR fortran/95342 + * gfortran.dg/pr95342.f90: New test. + +2020-12-03 Ian Lance Taylor <iant@golang.org> + + * go.test/go-test.exp (go-gc-tests): Add -I. when building all + sources in a directory (errorcheckdir, compiledir, rundir, + rundircmpout). + +2020-12-03 Jason Merrill <jason@redhat.com> + + PR c++/98019 + * g++.dg/cpp2a/concepts-nodiscard1.C: New test. + +2020-12-03 Uroš Bizjak <ubizjak@gmail.com> + Jakub Jelinek <jakub@redhat.com> + + PR target/98086 + * gcc.target/i386/pr98086.c: New test. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + PR c++/98115 + PR c++/98116 + * g++.dg/template/pr98115.C: New. + * g++.dg/template/pr98116.C: New. + +2020-12-03 Andreas Krebbel <krebbel@linux.ibm.com> + + * gcc.target/s390/stack-clash-4.c: New test. + +2020-12-03 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/undef_1.c: New test. + +2020-12-03 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.dg/pr98099.c: New test. + +2020-12-03 Eric Botcazou <ebotcazou@adacore.com> + + * g++.dg/cpp2a/pr98082.C: New test. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/93121 + * g++.dg/cpp2a/bit-cast1.C: New test. + * g++.dg/cpp2a/bit-cast2.C: New test. + * g++.dg/cpp2a/bit-cast3.C: New test. + * g++.dg/cpp2a/bit-cast4.C: New test. + * g++.dg/cpp2a/bit-cast5.C: New test. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/cpp2a/consteval-defarg2.C: New test. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/98104 + * g++.dg/warn/pr98104.C: New test. + +2020-12-03 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512bw-pr96906-1.c: New test. + * gcc.target/i386/pr96906-1.c: Add -mno-avx512f. + +2020-12-03 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512bw-vmovdqu16-1.c: Adjust testcase to + make sure only masked load instruction is generated. + * gcc.target/i386/avx512bw-vmovdqu8-1.c: Ditto. + * gcc.target/i386/avx512f-vmovapd-1.c: Ditto. + * gcc.target/i386/avx512f-vmovaps-1.c: Ditto. + * gcc.target/i386/avx512f-vmovdqa32-1.c: Ditto. + * gcc.target/i386/avx512f-vmovdqa64-1.c: Ditto. + * gcc.target/i386/avx512vl-vmovapd-1.c: Ditto. + * gcc.target/i386/avx512vl-vmovaps-1.c: Ditto. + * gcc.target/i386/avx512vl-vmovdqa32-1.c: Ditto. + * gcc.target/i386/avx512vl-vmovdqa64-1.c: Ditto. + * gcc.target/i386/pr97642-1.c: New test. + * gcc.target/i386/pr97642-2.c: New test. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * g++.dg/parse/defarg17.C: New test. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp2a/consteval-defarg1.C: New test. + +2020-12-03 Hongyu Wang <hongyu.wang@intel.com> + + PR target/97770 + * gcc.target/i386/avx512bitalg-pr97770-1.c: New test. + * gcc.target/i386/avx512vpopcntdq-pr97770-1.c: Likewise. + * gcc.target/i386/avx512vpopcntdq-pr97770-2.c: Likewise. + * gcc.target/i386/avx512vpopcntdqvl-pr97770-1.c: Likewise. + +2020-12-03 Alexandre Oliva <oliva@adacore.com> + + * lib/options.exp (check_for_options_with_filter): Detect + unavailable compiler for the selected language, and bail out + as unsupported. + +2020-12-03 Martin Sebor <msebor@redhat.com> + + * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust expected warnings + to correctly reflect the maximum object size. + * gcc.dg/tree-ssa/builtin-sprintf-warn-11.c: Same. + * gcc.dg/tree-ssa/builtin-sprintf-warn-18.c: Same. + +2020-12-03 Ilya Leoshkevich <iii@linux.ibm.com> + + * gcc.target/s390/builtin-constant-p-threading.c: New test. + 2020-12-03 Peter Bergner <bergner@linux.ibm.com> PR c++/97947 diff --git a/gcc/testsuite/g++.dg/asan/asan_test.cc b/gcc/testsuite/g++.dg/asan/asan_test.cc index 5f2e2c2..dbf1a6a 100644 --- a/gcc/testsuite/g++.dg/asan/asan_test.cc +++ b/gcc/testsuite/g++.dg/asan/asan_test.cc @@ -829,7 +829,7 @@ NOINLINE static int LargeFunction(bool do_bad_access) { x[18]++; x[19]++; - delete x; + delete[] x; return res; } diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast6.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast6.C new file mode 100644 index 0000000..4b70da1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast6.C @@ -0,0 +1,31 @@ +// PR libstd++/93121 +// { dg-do compile { target c++20 } } + +namespace std +{ +enum class byte : unsigned char {}; +template <typename To, typename From> +constexpr To +bit_cast (const From &from) +{ + return __builtin_bit_cast (To, from); +} +} + +struct S { unsigned short s[2]; }; +constexpr std::byte from1[sizeof (S)]{}; +constexpr auto to1 = std::bit_cast<S>(from1); +constexpr unsigned char from2[sizeof (S)]{}; +constexpr auto to2 = std::bit_cast<S>(from2); + +constexpr bool +cmp (const S &s1, const S &s2) +{ + for (int i = 0; i < sizeof (s1.s) / sizeof (s1.s[0]); i++) + if (s1.s[i] != s2.s[i]) + return false; + return true; +} + +static_assert (cmp (to1, S{})); +static_assert (cmp (to2, S{})); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-nodiscard1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-nodiscard1.C index 28ce29b..907e68b 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-nodiscard1.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-nodiscard1.C @@ -1,5 +1,6 @@ // PR c++/98019 // { dg-do compile { target c++20 } } +// { dg-excess-errors *-*-* } template <class T, class U> concept same_as = __is_same_as (T, U); diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class40.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class40.C new file mode 100644 index 0000000..d193544 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class40.C @@ -0,0 +1,79 @@ +// PR c++/93083 +// { dg-do compile { target c++20 } } + +template<unsigned N> +struct FixedString +{ + char buf[N + 1]{}; + constexpr FixedString(char const* s) { + for (unsigned i = 0; i != N; ++i) buf[i] = s[i]; + } + + auto operator<=>(const FixedString&) const = default; + constexpr operator char const*() const { return buf; } + constexpr static unsigned size() noexcept { return N; } +}; + +template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>; + +template <FixedString... names> +struct name_list +{ + template <FixedString name> + using add_name = name_list< + names..., + FixedString<name.size()>{ name } + >; +}; + + +int main() +{ + using names = + name_list<> + ::add_name<"Zaphod Beeblebrox">; + +} + +// ---------------- + +template <int N> struct literal { + constexpr literal(const char (&input)[N]) noexcept { } + constexpr literal(const literal &) noexcept { } +}; + +template <literal Name, int id> struct field { }; + +template <literal Name> struct field<Name, 1u> { }; + +// ---------------- + +template <int N> +struct use_as_nttp {}; + +template <use_as_nttp Value> +struct has_nttp {}; + +template <use_as_nttp Value> +using has_nttp_2 = has_nttp<Value>; + +// ---------------- + +using size_t = decltype(sizeof(0)); + +template <size_t N> +struct string_literal +{ + constexpr string_literal(const char*) {} + string_literal(string_literal const&) = default; +}; +template <size_t N> +string_literal(const char (&)[N]) -> string_literal<N - 1>; + +template <string_literal Str> +struct type_string { }; + +template <string_literal Str> +void foo() { + type_string<Str>{}; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc1.C b/gcc/testsuite/g++.dg/cpp2a/srcloc1.C index 6e19ff7..029a037 100644 --- a/gcc/testsuite/g++.dg/cpp2a/srcloc1.C +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc1.C @@ -88,7 +88,7 @@ quux () const char *file1 = source_location::current ().file_name (); const char *file2 = __FILE__; const char *function1 = source_location::current ().function_name (); - const char *function2 = __FUNCTION__; + const char *function2 = __PRETTY_FUNCTION__; int line1 = source_location::current ().line (); int line2 = __LINE__ - 1; int column diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc15.C b/gcc/testsuite/g++.dg/cpp2a/srcloc15.C index 30e5845..d02617e 100644 --- a/gcc/testsuite/g++.dg/cpp2a/srcloc15.C +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc15.C @@ -44,12 +44,12 @@ struct S { source_location loc = source_location::current (); constexpr S (int l, source_location loc = source_location::current ()) - : func(__FUNCTION__), line(l), loc(loc) + : func(__PRETTY_FUNCTION__), line(l), loc(loc) {} constexpr S (double) - : func(__FUNCTION__), line(__LINE__) - // ^ column 38 + : func(__PRETTY_FUNCTION__), line(__LINE__) + // ^ column 45 {} }; @@ -73,7 +73,7 @@ bar () // ^ column 49 const source_location *d[3] = { &a, &b, &c }; const char *file1 = __FILE__; - const char *function1 = __FUNCTION__; + const char *function1 = __PRETTY_FUNCTION__; for (int j = 0; j < 3; j++) { int i= 0; @@ -104,7 +104,7 @@ bar () return false; if (e.loc.column () != 9) return false; - if (f.loc.column () != 38) + if (f.loc.column () != 45) return false; return true; } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc17.C b/gcc/testsuite/g++.dg/cpp2a/srcloc17.C index 16704d0..a02ea48 100644 --- a/gcc/testsuite/g++.dg/cpp2a/srcloc17.C +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc17.C @@ -46,12 +46,12 @@ struct S { source_location loc = source_location::current (); constexpr S (int l, source_location loc = source_location::current ()) - : func(__FUNCTION__), line(l), loc(loc) + : func(__PRETTY_FUNCTION__), line(l), loc(loc) {} constexpr S (double) - : func(__FUNCTION__), line(__LINE__) - // ^ column 38 + : func(__PRETTY_FUNCTION__), line(__LINE__) + // ^ column 45 {} }; @@ -76,7 +76,7 @@ bar () // ^ column 48 const source_location *d[3] = { &a, &b, &c }; const char *file1 = __FILE__; - const char *function1 = b.function_name (); + const char *function1 = __PRETTY_FUNCTION__; for (int j = 0; j < 3; j++) { int i= 0; @@ -107,7 +107,7 @@ bar () return false; if (e.loc.column () != 8) return false; - if (f.loc.column () != 38) + if (f.loc.column () != 45) return false; return true; } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc2.C b/gcc/testsuite/g++.dg/cpp2a/srcloc2.C index 5ef09bb..4e0b960 100644 --- a/gcc/testsuite/g++.dg/cpp2a/srcloc2.C +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc2.C @@ -92,7 +92,7 @@ quux () const char *file1 = source_location::current ().file_name (); const char *file2 = __FILE__; const char *function1 = source_location::current ().function_name (); - const char *function2 = __FUNCTION__; + const char *function2 = __PRETTY_FUNCTION__; int line1 = source_location::current ().line (); int line2 = __LINE__ - 1; int column diff --git a/gcc/testsuite/g++.dg/opt/pr98130.C b/gcc/testsuite/g++.dg/opt/pr98130.C new file mode 100644 index 0000000..0af55ef --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr98130.C @@ -0,0 +1,25 @@ +// PR c++/98130 +// { dg-do run { target c++11 } } +// { dg-options "-O2" } + +#include <new> + +typedef int *T; + +static unsigned char storage[sizeof (T)] alignas (T); +static T *p = (T *) storage; + +static inline __attribute__((__always_inline__)) void +foo (T value) +{ + new (p) T(value); +} + +int +main () +{ + int a; + foo (&a); + if (!*p) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/template/pr98116.C b/gcc/testsuite/g++.dg/template/pr98116.C index d3398d2..874c590 100644 --- a/gcc/testsuite/g++.dg/template/pr98116.C +++ b/gcc/testsuite/g++.dg/template/pr98116.C @@ -1,5 +1,11 @@ // PR 98116, ICE with stripping typedef array type // { dg-do compile { target c++11 } } +// { dg-additional-options {--param=hash-table-verification-limit=10000000 -fchecking=2} } +// { dg-ice "spec_hasher::equal" } + +// We get confused by alias templates that alias the same type. +// { dg-prune-output "hash table checking failed" } + namespace std { struct is_convertible; template <typename _Tp> using remove_pointer_t = typename _Tp ::type; diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-2.C b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-2.C new file mode 100644 index 0000000..9d4d2a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-2.C @@ -0,0 +1,274 @@ +/* PR ????? - No warning on attempts to access free object + Verify that freeing unallocated objects referenced either directly + or through pointers is diagnosed. + { dg-do compile } + { dg-options "-O2 -Wall -Wfree-nonheap-object" } */ + +typedef __INTPTR_TYPE__ intptr_t; +typedef __SIZE_TYPE__ size_t; + +extern "C" +{ + void free (void*); + extern void* malloc (size_t); + extern void* realloc (void *p, size_t); +} + +void sink (void*, ...); +#define sink(...) sink (0, __VA_ARGS__) + +extern char ecarr[]; +extern void* eparr[]; + +extern char *eptr; + +void* source (void); + +void nowarn_free (void *p, void **pp, size_t n, intptr_t iptr) +{ + free (p); + + p = 0; + free (p); + + p = malloc (n); + sink (p); + free (p); + + p = malloc (n); + sink (p); + + p = realloc (p, n * 2); + sink (p); + free (p); + + free ((void*)iptr); + + p = source (); + free (p); + + p = source (); + p = (char*)p - 1; + free (p); + + free (*pp); +} + +void warn_free_extern_arr (void) +{ + free (ecarr); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_extern_arr_offset (int i) +{ + char *p = ecarr + i; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_cstint (void) +{ + void *p = (void*)1; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_func (void) +{ + void *p = (void*)warn_free_func; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_string (int i) +{ + { + char *p = (char*)"123"; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char *p = (char*)"234" + 1; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char *p = (char*)"345" + i; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + + if (i >= 0) + { + char *p = (char*)"456" + i; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } +} + +void warn_free_local_arr (int i) +{ + { + char a[4]; + sink (a); + free (a); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char b[5]; + sink (b); + + char *p = b + 1; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char c[6]; + sink (c); + + char *p = c + i; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } +} + + +void warn_free_vla (int n, int i) +{ + { + int vla[n], *p = vla; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + + { + int vla[n + 1], *p = vla + 1; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + int vla[n + 2], *p = vla + i; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } +} + + +void nowarn_free_extern_ptrarr (void) +{ + free (*eparr); +} + +void nowarn_free_extern_ptrarr_offset (int i) +{ + void *p = eparr[i]; + free (p); +} + + +void warn_free_extern_ptrarr (void) +{ + free (eparr); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_extern_ptrarr_offset (int i) +{ + void *p = &eparr[i]; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void nowarn_free_local_ptrarr (int i) +{ + void* a[4]; + sink (a); + free (a[0]); + free (a[1]); + free (a[i]); +} + + +void nowarn_free_extern_ptr (void) +{ + free (eptr); +} + +void nowarn_free_extern_ptr_offset (int i) +{ + char *p = eptr + i; + free (p); +} + +void warn_free_extern_ptr_pos_offset (int i) +{ + if (i <= 0) + i = 1; + + char *q = eptr + i; + free (q); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void nowarn_free_parm_offset (char *p, int i) +{ + char *q = p + i; + free (q); +} + +void nowarn_free_parm_neg_offset (char *p, int i) +{ + if (i >= 0) + i = -1; + + char *q = p + i; + free (q); +} + +void warn_free_parm_pos_offset (char *p, int i) +{ + if (i <= 0) + i = 1; + + char *q = p + i; + free (q); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +struct Members +{ + char a[4], *p, *q; +}; + +extern struct Members em; + +void nowarn_free_member_ptr (struct Members *pm, int i) +{ + char *p = em.p; + free (p); + p = em.q + i; + free (p); + + free (pm->q); + p = pm->p; + free (pm); + free (p); +} + +void nowarn_free_struct_cast (intptr_t *p) +{ + struct Members *q = (struct Members*)*p; + if (q->p == 0) + free (q); // { dg-bogus "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_member_array (void) +{ + char *p = em.a; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_member_array_off (int i) +{ + char *p = em.a + i; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object.C b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object.C new file mode 100644 index 0000000..82b081a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object.C @@ -0,0 +1,124 @@ +/* PR ????? - No warning on attempts to access free object + Verify that attempts to deallocate objects by pointers with nonzero + offsets is diagnosed. + { dg-do compile } + { dg-options "-O2 -Wall -Wfree-nonheap-object" } */ + +typedef __INTPTR_TYPE__ intptr_t; +typedef __SIZE_TYPE__ size_t; + +void sink (void*, ...); + +extern char ecarr[]; +extern void* eparr[]; + +extern char *eptr; + +char* source (void); + +void nowarn_op_delete (void *p, void ***ppp, size_t n, intptr_t iptr) +{ + operator delete (p); + + p = 0; + operator delete (p); + + p = operator new (n); + sink (p); + operator delete (p); + + p = operator new (n); + sink (p); + + operator delete ((void*)iptr); + + p = source (); + operator delete (p); + + p = source (); + p = (char*)p - 1; + operator delete (p); + + operator delete (**ppp); + operator delete (*ppp); + operator delete (ppp); +} + +void warn_op_delete_cstaddr (void *p) +{ + operator delete (p); + p = (void*)~0; + operator delete (p); // { dg-warning "called on a pointer to an unallocated object" } */ +} + +void warn_op_delete_funcaddr () +{ + void *p = (void*)&warn_op_delete_funcaddr; + operator delete (p); // { dg-warning "called on unallocated object 'void warn_op_delete_funcaddr()" } */ +} + +void warn_op_delete_string (void *p) +{ + operator delete (p); + p = (void*)""; + operator delete (p); // { dg-warning "called on a pointer to an unallocated object" } */ +} + +void warn_op_delete_ptr_to_self (void *p) +{ + operator delete (p); + p = &p; + operator delete (p); // { dg-warning "called on unallocated object 'p'" } */ +} + +void nowarn_op_new_delete (size_t n) +{ + void *p = operator new (n); + sink (p); + operator delete (p); +} + +void nowarn_op_new_delete_ptr_plus (size_t n) +{ + void *p0_1 = operator new (n); + void *p1 = (char*)p0_1 + 1; + sink (p0_1, p1); + void *p0_2 = (char*)p1 - 1; + sink (p0_1, p1, p0_2); + operator delete (p0_2); +} + +void warn_op_new_delete_cstoff (size_t n) +{ + void *p = operator new (n); + void *q = (char*)p + 1; + sink (p, q); + operator delete (q); // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer '\[^'\]+' with nonzero offset 1" } +} + +void warn_op_new_delete_ptr_plus (size_t n) +{ + char *p = (char*)operator new (n); + sink (++p); + operator delete (p); // { dg-warning "called on pointer '\[^']+' with nonzero offset 1" } +} + +void warn_op_delete_funcret_plus (size_t n) +{ + char *p = source (); + sink (++p); + operator delete (p); // { dg-warning "called on pointer '\[^']+' with nonzero offset 1" } +} + +void warn_op_delete_eptr_plus (int i) +{ + extern char *ecp; + + if (i < 1) + i = 1; + + char *p = ecp + i; + sink (p); + + operator delete (p); // { dg-warning "called on pointer '\[^']+' with nonzero offset \\\[1, \\d+]" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object.s b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object.s new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object.s diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C new file mode 100644 index 0000000..7ecc99a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C @@ -0,0 +1,185 @@ +/* PR middle-end/94527 - Add an attribute that marks a function as freeing + an object + The detection doesn't require optimization. + { dg-do compile } + { dg-options "-Wall" } */ + +#define A(...) __attribute__ ((malloc (__VA_ARGS__))) + +typedef __SIZE_TYPE__ size_t; + +extern "C" { + void free (void *); + void* realloc (void *, size_t); +} + +void sink (void *); + +void mydealloc (int, void*); +void* A (mydealloc, 2) myalloc (void*); + + +void my_delete (const char*, void*); +void my_array_delete (const char*, void*); + +typedef void OpDelete1 (void*); +typedef void OpDelete2 (void*, size_t); + +A ((OpDelete1*)operator delete, 1) +#if __cplusplus >= 201402L +A ((OpDelete2*)operator delete, 1) +#endif +A (my_delete, 2) +int* my_new (size_t); + +A ((OpDelete1*)operator delete[], 1) +#if __cplusplus >= 201402L +A ((OpDelete2*)operator delete[], 1) +#endif +A (my_array_delete, 2) +int* my_array_new (size_t); + + +void test_my_new () +{ + { + void *p = my_new (1); + operator delete (p); + } + { + void *p = my_new (1); + sink (p); + operator delete (p); + } + { + int *p = my_new (1); + sink (p); + delete p; + } + + { + void *p = my_new (1); + // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + operator delete[] (p); + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 } + } + { + void *p = my_new (1); + // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + operator delete[] (p); + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 } + } + { + int *p = my_new (1); + sink (p); + delete[] p; + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 } + } + + { + void *p = my_new (1); + my_delete ("1", p); + } + { + void *p = my_new (1); + sink (p); + my_delete ("2", p); + } + + { + void *p = my_new (1); + // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + my_array_delete ("3", p); + // { dg-warning "'void my_array_delete\\\(const char\\\*, void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + void *p = my_new (1); + // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + free (p); + // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + void *p = my_new (1); + // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + p = realloc (p, 123); + // { dg-warning "'void\\\* realloc\\\(void\\\*, size_t\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} + + +void test_my_array_new () +{ + { + void *p = my_array_new (1); + operator delete[] (p); + } + { + void *p = my_array_new (1); + sink (p); + operator delete[] (p); + } + { + int *p = my_array_new (1); + sink (p); + delete[] p; + } + + { + void *p = my_array_new (1); + // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + operator delete (p); + // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 } + } + { + void *p = my_array_new (1); + // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + operator delete (p); + // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 } + } + { + int *p = my_array_new (1); + sink (p); + delete p; + // { dg-warning "'void operator delete\\\(void\\\*\[^\)\]*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 } + } + + { + void *p = my_array_new (1); + my_array_delete ("1", p); + } + { + void *p = my_array_new (1); + sink (p); + my_array_delete ("2", p); + } + { + void *p = my_array_new (1); + // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + my_delete ("3", p); + // { dg-warning "'void my_delete\\\(const char\\\*, void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + void *p = my_array_new (1); + // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + free (p); + // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + void *p = my_array_new (1); + // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 } + sink (p); + p = realloc (p, 123); + // { dg-warning "'void\\\* realloc\\\(void\\\*, size_t\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc.C b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc.C new file mode 100644 index 0000000..682db6f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc.C @@ -0,0 +1,27 @@ +/* PR middle-end/94527 - Add an attribute that marks a function as freeing + an object + { dg-do compile { target c++11 } } + { dg-options "-Wall" } */ + +#define A(...) __attribute__ ((malloc (__VA_ARGS__))) + +typedef __SIZE_TYPE__ size_t; + +void mydealloc (int, void*); +void* A (mydealloc, 2) myalloc (void*); + + +void* A (operator delete, 1) + bad_new (size_t); // { dg-error "attribute argument 1 is ambiguous" } +void* A (operator delete[], 1) + bad_array_new (size_t); // { dg-error "attribute argument 1 is ambiguous" } + +void my_delete (const char*, void*); +void my_array_delete (const char*, void*); + +typedef void OpDelete (void*); + +int* A ((OpDelete*)operator delete, 1) A (my_delete, 2) + my_new (size_t); +int* A ((OpDelete*)operator delete[], 1) A (my_array_delete, 2) + my_array_new (size_t); diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C new file mode 100644 index 0000000..ed1090b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C @@ -0,0 +1,212 @@ +/* PR c++/90629 - Support for -Wmismatched-new-delete + The detection doesn't require optimization. + { dg-do compile } + { dg-options "-Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +extern "C" { + void free (void *); + void* malloc (size_t); + void* realloc (void *, size_t); + char* strdup (const char *); + char* strndup (const char *, size_t); +} + +void sink (void *); + +void nowarn_op_new_delete (int n) +{ + void *p = operator new (n); + sink (p); + operator delete (p); +} + +void nowarn_new_delete (int n) +{ + { + char *p = new char; + sink (p); + delete p; + } + + { + char *p = new char[n]; + sink (p); + delete[] p; + } +} + +/* Verify a warning for calls to free() with a pointer returned from + a call to operator new() or the new expressopm. */ + +void warn_new_free (int n) +{ + { + void *p = operator new (n); + // { dg-message "returned from a call to 'void\\\* operator new\\\(" "note" { target *-*-* } .-1 } + sink (p); + free (p); + // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + { + char *p = new char[n]; + // { dg-message "returned from a call to 'void\\\* operator new \\\[" "note" { target *-*-* } .-1 } + sink (p); + free (p); + // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} + + +/* Verify a warning for calls to realloc() with a pointer returned from + a call to operator new() or the new expressopm. */ + +void warn_new_realloc (int n) +{ + { + void *p = operator new (n); + // { dg-message "returned from a call to 'void\\\* operator new\\\(" "note" { target *-*-* } .-1 } + sink (p); + p = realloc (p, n * 2); + // { dg-warning "'void\\\* realloc\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + sink (p); + } + { + void *p = new char[n]; + // { dg-message "returned from a call to 'void\\\* operator new \\\[" "note" { target *-*-* } .-1 } + sink (p); + p = realloc (p, n * 2); + // { dg-warning "'void\\\* realloc\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + sink (p); + } +} + + +/* Verify a warning for a call to operator_delete() with a pointer returned + from a call to malloc(). */ + +void warn_malloc_op_delete (int n) +{ + char *p = (char *)malloc (n); + // { dg-message "returned from a call to 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 } + sink (p); + operator delete (p); + // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } +} + + +/* Verify a warning for an invocation of either form of the delete + expression with a pointer returned from a call to malloc(). */ + +void warn_malloc_delete (int n) +{ + { + char *p = (char *)malloc (n); + // { dg-message "returned from a call to 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 } + sink (p); + /* C++98 calls operator delete (void*) but later versions call + operator delete (void*, size_t). The difference doesn't matter + here so verify just that some operator delete is called. */ + delete p; + // { dg-warning "'void operator delete\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + char *p = (char *)malloc (n); + // { dg-message "returned from a call to 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 } + sink (p); + delete[] p; + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} + + +/* Verify a warning for an invocation of either form of the delete + expression with a pointer returned from a call to realloc(). */ + +void warn_realloc_delete (void *p1, void *p2, int n) +{ + { + char *q = (char *)realloc (p1, n); + // { dg-message "returned from a call to 'void\\\* realloc\\\(" "note" { target *-*-* } .-1 } + sink (q); + /* C++98 calls operator delete (void*) but later versions call + operator delete (void*, size_t). The difference doesn't matter + here so verify just that some operator delete is called. */ + delete q; + // { dg-warning "'void operator delete\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + char *q = (char *)realloc (p2, n); + // { dg-message "returned from a call to 'void\\\* realloc\\\(" "note" { target *-*-* } .-1 } + sink (q); + delete[] q; + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} + + +/* Verify a warning for an invocation of either form of the delete + expression with a pointer returned from a call to strdup(). */ + +void warn_strdup_delete (const char *s1, const char *s2) +{ + { + char *q = strdup (s1); + // { dg-message "returned from a call to 'char\\\* strdup\\\(" "note" { target *-*-* } .-1 } + sink (q); + /* C++98 calls operator delete (void*) but later versions call + operator delete (void*, size_t). The difference doesn't matter + here so verify just that some operator delete is called. */ + delete q; + // { dg-warning "'void operator delete\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + char *q = strdup (s2); + // { dg-message "returned from a call to 'char\\\* strdup\\\(" "note" { target *-*-* } .-1 } + sink (q); + delete[] q; + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} + + + +/* Verify a warning for an invocation of either form of the delete + expression with a pointer returned from a call to strndup(). */ + +void warn_strdup_delete (const char *s1, const char *s2, size_t n) +{ + { + char *q = strndup (s1, n); + // { dg-message "returned from a call to 'char\\\* strndup\\\(" "note" { target *-*-* } .-1 } + sink (q); + /* C++98 calls operator delete (void*) but later versions call + operator delete (void*, size_t). The difference doesn't matter + here so verify just that some operator delete is called. */ + delete q; + // { dg-warning "'void operator delete\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } + + { + char *q = strndup (s2, n); + // { dg-message "returned from a call to 'char\\\* strndup\\\(" "note" { target *-*-* } .-1 } + sink (q); + delete[] q; + // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 } + } +} + + +struct Base { virtual ~Base (); }; +struct Derived: Base { }; + +void warn_new_free_base_derived () +{ + Base *p = new Derived (); + sink (p); + free (p); // { dg-warning "\\\[-Wmismatched-new-delete" } +} diff --git a/gcc/testsuite/g++.dg/warn/delete-array-1.C b/gcc/testsuite/g++.dg/warn/delete-array-1.C index c3af713..95fa7d4 100644 --- a/gcc/testsuite/g++.dg/warn/delete-array-1.C +++ b/gcc/testsuite/g++.dg/warn/delete-array-1.C @@ -5,7 +5,7 @@ struct S { int a [1]; } s; void foo (S *p) { - delete a; // { dg-warning "deleting array" } - delete s.a; // { dg-warning "deleting array" } - delete p->a; // { dg-warning "deleting array" } + delete a; // { dg-warning "deleting array|-Wfree-nonheap-object" } + delete s.a; // { dg-warning "deleting array|-Wfree-nonheap-object" } + delete p->a; // { dg-warning "deleting array|-Wfree-nonheap-object" } } diff --git a/gcc/testsuite/g++.old-deja/g++.other/delete2.C b/gcc/testsuite/g++.old-deja/g++.other/delete2.C index 1d0554f..76ae355 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/delete2.C +++ b/gcc/testsuite/g++.old-deja/g++.other/delete2.C @@ -9,5 +9,7 @@ void bar(foo a) { delete[] a; // should be accepted char b[1]; delete b; // { dg-warning "deleting array" } expecting pointer type + // { dg-warning "-Wfree-nonheap-object" "" { target *-*-* } .-1 } delete[] b; // { dg-warning "deleting array" } expecting pointer type + // { dg-warning "-Wfree-nonheap-object" "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/gcc.dg/Wfree-nonheap-object-2.c b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-2.c new file mode 100644 index 0000000..2b00d77 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-2.c @@ -0,0 +1,279 @@ +/* PR ????? - No warning on attempts to access free object + Verify that attempting to reallocate unallocated objects referenced + either directly or through pointers is diagnosed. + { dg-do compile } + { dg-options "-O2 -Wall -Wfree-nonheap-object" } */ + +typedef __SIZE_TYPE__ size_t; + +extern void free (void*); +extern void* alloca (size_t); +extern void* realloc (void*, size_t); + +void sink (void*, ...); + +extern void* eparr[]; +extern char *eptr; + +extern size_t n; + + +void nowarn_realloc (void *p, size_t n) +{ + char *q = realloc (p, n); + sink (q); + + q = realloc (0, n); + sink (q); + + q = realloc (q, n * 2); + sink (q); +} + +/* Verify that calling realloc on a pointer to an unknown object minus + some nonzero offset isn't diagnosed, but a pointer plus a positive + offset is (a positive offset cannot point at the beginning). */ + +void test_realloc_offset (char *p1, char *p2, char *p3, size_t n, int i) +{ + char *q; + q = realloc (p1 - 1, n); + sink (q); + + q = realloc (p2 + 1, n); // { dg-warning "'realloc' called on pointer 'p2' with nonzero offset 1" } + sink (q); + + q = realloc (p3 + i, n); + sink (q); +} + +void warn_realloc_extern_arr (void) +{ + extern char ecarr[]; // { gg-message "declared here" } + char *p = ecarr; + char *q = realloc (p, n); // { dg-warning "'realloc' called on unallocated object 'ecarr'" } + sink (q); +} + +void warn_realloc_extern_arr_offset (int i) +{ + extern char ecarr[]; + char *p = ecarr + i; + char *q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); +} + + +void warn_realloc_string (int i) +{ + char *p, *q; + { + p = "123"; + sink (p); + q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + { + p = "234" + 1; + sink (p); + q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + { + p = "123" + i; + sink (p); + q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } +} + + +void warn_realloc_alloca (int n, int i) +{ + char *p, *q; + { + p = alloca (n); + sink (p); + q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + { + p = (char*)alloca (n + 1); + sink (p); + q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + { + p = (char*)alloca (n + 2) + i; + sink (p); + q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } +} + + +void warn_realloc_local_arr (int i) +{ + char *q; + { + char a[4]; + sink (a); + q = realloc (a, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + + { + char b[5]; + sink (b); + q = realloc (b + 1, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + + { + char c[6]; + sink (c); + q = realloc (&c[2], n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + + { + char d[7]; + sink (d); + q = realloc (&d[i], n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } +} + +void warn_realloc_vla (int n1, int n2, int i) +{ + char *q; + { + char vla[n1]; + sink (vla); + q = realloc (vla, n2); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + + { + char vlb[n1 + 1]; + sink (vlb); + q = realloc (vlb + 1, n2);// { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + + { + char vlc[n1 + 2]; + sink (vlc); + q = realloc (&vlc[2], n2);// { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } + + { + char vld[7]; + sink (vld); + q = realloc (&vld[i], n2);// { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); + } +} + +void nowarn_realloc_extern_ptrarr (void) +{ + char *q = realloc (*eparr, n); + sink (q); +} + +void nowarn_realloc_extern_ptrarr_offset (int i) +{ + char *p = eparr[i]; + char *q = realloc (p, n); + sink (q); +} + + +void warn_realloc_extern_ptrarr (void) +{ + char *q = realloc (eparr, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); +} + +void warn_realloc_extern_ptrarr_offset (int i) +{ + void *p = eparr + i; + void *q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); +} + + +void nowarn_realloc_extern_ptr (void) +{ + char *q = realloc (eptr, n); + sink (q); +} + +void nowarn_realloc_extern_ptr_offset (int i) +{ + char *p = eptr + i; + char *q = realloc (p, n); + sink (q); +} + + +void warn_realloc_extern_ptr_pos_offset (int i) +{ + if (i <= 0) + i = 1; + + char *p = eptr + i; + char *q = realloc (p, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); +} + + +void nowarn_realloc_parm_offset (char *p, int i) +{ + char *q = p + i; + q = realloc (q, n); + sink (q); +} + +void nowarn_realloc_parm_neg_offset (char *p, int i) +{ + if (i >= 0) + i = -1; + + char *q = p + i; + q = realloc (q, n); + sink (q); +} + +void warn_realloc_parm_pos_offset (char *p, int i) +{ + if (i <= 0) + i = 1; + + char *q = p + i; + q = realloc (q, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); +} + +void nowarn_realloc_deref_parm_pos_offset (void **p, int i) +{ + if (i <= 0) + i = 1; + + // The offset is from p, not *p. + void *q = *(p + i); + q = realloc (q, n); + sink (q); +} + +void warn_realloc_deref_parm_pos_offset (void **p, int i) +{ + if (i <= 0) + i = 1; + + // Unlike in the function above the offset is from *p. + void *q = *p + i; + q = realloc (q, n); // { dg-warning "\\\[-Wfree-nonheap-object" } + sink (q); +} diff --git a/gcc/testsuite/gcc.dg/Wfree-nonheap-object-3.c b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-3.c new file mode 100644 index 0000000..a472b93 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-3.c @@ -0,0 +1,57 @@ +/* PR ????? - No warning on attempts to access free object + Verify that freeing unallocated objects referenced indirectly through + pointers obtained from function calls is diagnosed. + { dg-do compile } + { dg-options "-O2 -Wall -Wfree-nonheap-object" } */ + +typedef __SIZE_TYPE__ size_t; + +extern void free (void*); +extern char* memchr (const void*, int, size_t); +extern char* strchr (const char*, int); + +void sink (void*, ...); + +extern char ecarr[]; +extern void* eparr[]; + +extern char *eptr; + + +void warn_free_memchr_ecarr (int x, size_t n) +{ + char *p = memchr (ecarr, x, n); + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_memchr_ecarr_offset (int i, int j, int x, size_t n) +{ + char *p = memchr (ecarr + i, x, n); + char *q = p + j; + sink (p, q); + free (q); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_memchr_local_arr (int x, size_t n) +{ + char a[8]; + sink (a); + + char *p = memchr (a, x, n); + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_memchr_local_arr_offset (int i, int j, int x, size_t n) +{ + char a[8]; + sink (a); + + char *p = memchr (a + i, x, n); + char *q = p + j; + sink (p, q); + free (q); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + diff --git a/gcc/testsuite/gcc.dg/Wfree-nonheap-object.c b/gcc/testsuite/gcc.dg/Wfree-nonheap-object.c new file mode 100644 index 0000000..bb222cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wfree-nonheap-object.c @@ -0,0 +1,273 @@ +/* PR ????? - No warning on attempts to access free object + Verify that freeing unallocated objects referenced either directly + or through pointers is diagnosed. In most cases this doesn't require + optimization. + { dg-do compile } + { dg-options "-Wall -Wfree-nonheap-object" } */ + +typedef __INTPTR_TYPE__ intptr_t; +typedef __SIZE_TYPE__ size_t; + +extern void free (void*); +extern void* malloc (size_t); +extern void* realloc (void *p, size_t); + +void sink (void*, ...); + +extern char ecarr[]; +extern void* eparr[]; + +extern char *eptr; + +void* source (void); + +void nowarn_free (void *p, void **pp, size_t n, intptr_t iptr) +{ + free (p); + + p = 0; + free (p); + + p = malloc (n); + sink (p); + free (p); + + p = malloc (n); + sink (p); + + p = realloc (p, n * 2); + sink (p); + free (p); + + free ((void*)iptr); + + p = source (); + free (p); + + p = source (); + p = (char*)p - 1; + free (p); + + free (*pp); +} + +void warn_free_extern_arr (void) +{ + free (ecarr); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_extern_arr_offset (int i) +{ + char *p = ecarr + i; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_cstint (void) +{ + void *p = (void*)1; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_func (void) +{ + void *p = warn_free_func; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_string (int i) +{ + { + char *p = "123"; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char *p = "234" + 1; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char *p = "345" + i; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + + if (i >= 0) + { + char *p = "456" + i; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } +} + +void warn_free_local_arr (int i) +{ + { + char a[4]; + sink (a); + free (a); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char b[5]; + sink (b); + + char *p = b + 1; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + char c[6]; + sink (c); + + char *p = c + i; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } +} + + +void warn_free_vla (int n, int i) +{ + { + int vla[n], *p = vla; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + + { + int vla[n + 1], *p = vla + 1; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } + { + int vla[n + 2], *p = vla + i; + sink (p); + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } + } +} + + +void nowarn_free_extern_ptrarr (void) +{ + free (*eparr); +} + +void nowarn_free_extern_ptrarr_offset (int i) +{ + char *p = eparr[i]; + free (p); +} + + +void warn_free_extern_ptrarr (void) +{ + free (eparr); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_extern_ptrarr_offset (int i) +{ + void *p = &eparr[i]; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +void nowarn_free_local_ptrarr (int i) +{ + void* a[4]; + sink (a); + free (a[0]); + free (a[1]); + free (a[i]); +} + + +void nowarn_free_extern_ptr (void) +{ + free (eptr); +} + +void nowarn_free_extern_ptr_offset (int i) +{ + char *p = eptr + i; + free (p); +} + +void nowarn_free_parm_offset (char *p, int i) +{ + char *q = p + i; + free (q); +} + +void nowarn_free_parm_neg_offset (char *p, int i) +{ + if (i >= 0) + i = -1; + + char *q = p + i; + free (q); +} + +struct Members +{ + char a[4], *p, *q; +}; + +extern struct Members em; + +void nowarn_free_member_ptr (struct Members *pm, int i) +{ + char *p = em.p; + free (p); + p = em.q + i; + free (p); + + free (pm->q); + p = pm->p; + free (pm); + free (p); +} + +void nowarn_free_struct_cast (intptr_t *p) +{ + struct Members *q = (struct Members*)*p; + if (q->p == 0) + free (q); // { dg-bogus "\\\[-Wfree-nonheap-object" } +} + + +void warn_free_member_array (void) +{ + char *p = em.a; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_member_array_off (int i) +{ + char *p = em.a + i; + free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + + +// Range information requires optimization. +#pragma GCC optimize "1" + +void warn_free_extern_ptr_pos_offset (int i) +{ + if (i <= 0) + i = 1; + + char *q = eptr + i; + free (q); // { dg-warning "\\\[-Wfree-nonheap-object" } +} + +void warn_free_parm_pos_offset (char *p, int i) +{ + if (i <= 0) + i = 1; + + char *q = p + i; + free (q); // { dg-warning "\\\[-Wfree-nonheap-object" } +} diff --git a/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c b/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c new file mode 100644 index 0000000..7c5d6ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c @@ -0,0 +1,252 @@ +/* PR middle-end/94527 - Add an attribute that marks a function as freeing + an object + Verify that attribute malloc with one or two arguments has the expected + effect on diagnostics. + { dg-options "-Wall -ftrack-macro-expansion=0" } */ + +#define A(...) __attribute__ ((malloc (__VA_ARGS__))) + +typedef struct FILE FILE; +typedef __SIZE_TYPE__ size_t; + +void free (void*); +void* malloc (size_t); +void* realloc (void*, size_t); + +int fclose (FILE*); +FILE* freopen (const char*, const char*, FILE*); +int pclose (FILE*); + +A (fclose) A (freopen, 3) + FILE* fdopen (int); +A (fclose) A (freopen, 3) + FILE* fopen (const char*, const char*); +A (fclose) A (freopen, 3) + FILE* fmemopen(void *, size_t, const char *); +A (fclose) A (freopen, 3) + FILE* freopen (const char*, const char*, FILE*); +A (pclose) A (freopen, 3) + FILE* popen (const char*, const char*); +A (fclose) A (freopen, 3) + FILE* tmpfile (void); + +void sink (FILE*); + + + void release (void*); +A (release) FILE* acquire (void); + +void nowarn_fdopen (void) +{ + { + FILE *q = fdopen (0); + if (!q) + return; + + fclose (q); + } + + { + FILE *q = fdopen (0); + if (!q) + return; + + q = freopen ("1", "r", q); + fclose (q); + } + + { + FILE *q = fdopen (0); + if (!q) + return; + + sink (q); + } +} + + +void warn_fdopen (void) +{ + { + FILE *q = fdopen (0); // { dg-message "returned from a call to 'fdopen'" "note" } + sink (q); + release (q); // { dg-warning "'release' called on pointer returned from a mismatched allocation function" } + } + { + FILE *q = fdopen (0); // { dg-message "returned from a call to 'fdopen'" "note" } + sink (q); + free (q); // { dg-warning "'free' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *q = fdopen (0); // { dg-message "returned from a call to 'fdopen'" "note" } + sink (q); + q = realloc (q, 7); // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" } + sink (q); + } +} + + +void nowarn_fopen (void) +{ + { + FILE *q = fopen ("1", "r"); + sink (q); + fclose (q); + } + + { + FILE *q = fopen ("2", "r"); + sink (q); + q = freopen ("3", "r", q); + sink (q); + fclose (q); + } + + { + FILE *q = fopen ("4", "r"); + sink (q); + } +} + + +void warn_fopen (void) +{ + { + FILE *q = fopen ("1", "r"); + sink (q); + release (q); // { dg-warning "'release' called on pointer returned from a mismatched allocation function" } + } + { + FILE *q = fdopen (0); + sink (q); + free (q); // { dg-warning "'free' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *q = fdopen (0); + sink (q); + q = realloc (q, 7); // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" } + sink (q); + } +} + + +void test_popen (void) +{ + { + FILE *p = popen ("1", "r"); + sink (p); + pclose (p); + } + + { + FILE *p; + p = popen ("2", "r"); // { dg-message "returned from a call to 'popen'" "note" } + sink (p); + fclose (p); // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" } + } + + { + /* freopen() can close a stream open by popen() but pclose() can't + close the stream returned from freopen(). */ + FILE *p = popen ("2", "r"); + sink (p); + p = freopen ("3", "r", p); // { dg-message "returned from a call to 'freopen'" "note" } + sink (p); + pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } + } +} + + +void test_tmpfile (void) +{ + { + FILE *p = tmpfile (); + sink (p); + fclose (p); + } + + { + FILE *p = tmpfile (); + sink (p); + p = freopen ("1", "r", p); + sink (p); + fclose (p); + } + + { + FILE *p = tmpfile (); // { dg-message "returned from a call to 'tmpfile'" "note" } + sink (p); + pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } + } +} + + +void warn_malloc (void) +{ + { + FILE *p = malloc (100); // { dg-message "returned from a call to 'malloc'" "note" } + sink (p); + fclose (p); // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *p = malloc (100); // { dg-message "returned from a call to 'malloc'" "note" } + sink (p); + p = freopen ("1", "r", p);// { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *p = malloc (100); // { dg-message "returned from a call to 'malloc'" "note" } + sink (p); + pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } + } +} + + +void test_acquire (void) +{ + { + FILE *p = acquire (); + release (p); + } + + { + FILE *p = acquire (); + sink (p); + release (p); + } + + { + FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } + sink (p); + fclose (p); // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } + sink (p); + pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } + sink (p); + p = freopen ("1", "r", p); // { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" } + sink (p); + } + + { + FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } + sink (p); + free (p); // { dg-warning "'free' called on pointer returned from a mismatched allocation function" } + } + + { + FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } + sink (p); + p = realloc (p, 123); // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" } + sink (p); + } +} diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c index c5bf1227c..26d8288 100644 --- a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c @@ -609,3 +609,5 @@ int test_49 (int i) *p = 1; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */ return x; } + +/* { dg-prune-output "\\\[-Wfree-nonheap-object" } */ diff --git a/gcc/testsuite/gcc.dg/attr-malloc.c b/gcc/testsuite/gcc.dg/attr-malloc.c new file mode 100644 index 0000000..14f1980 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-malloc.c @@ -0,0 +1,75 @@ +/* PR middle-end/94527 - Add an attribute that marks a function as freeing + an object + Verify that attribute malloc with one or two arguments is accepted where + intended and rejected where it's invalid. + { dg-options "-Wall -ftrack-macro-expansion=0" } */ + +#define A(...) __attribute__ ((malloc (__VA_ARGS__))) + +A (0) void* alloc_zero (int); // { dg-error "'malloc' attribute argument 1 does not name a function" } + +A ("") void* alloc_string (int); // { dg-error "'malloc' attribute argument 1 does not name a function" } + +int var; +A (var) void* alloc_var (int); // { dg-error "'malloc' attribute argument 1 does not name a function" } + +typedef struct Type { int i; } Type; +A (Type) void* alloc_type (int); // { dg-error "expected expression|identifier" } + +A (unknown) void* alloc_unknown (int); // { dg-error "'unknown' undeclared" } + +void fv_ (); // { dg-message "declared here" } +A (fv_) void* alloc_fv_ (int); // { dg-error "'malloc' attribute argument 1 must take a pointer type as its first argument" } + +void fvi (int); // { dg-message "declared here" } +A (fvi) void* alloc_fvi (int); // { dg-error "'malloc' attribute argument 1 must take a pointer type as its first argument; have 'int'" } + +void fvv (void); // { dg-message "declared here" } +A (fvv) void* alloc_fvv (int); // { dg-error "'malloc' attribute argument 1 must take a pointer type as its first argument; have 'void'" } + +void fvi_ (int, ...); // { dg-message "declared here" } +A (fvi_) void* alloc_fvi_ (int); // { dg-error "'malloc' attribute argument 1 must take a pointer type as its first argument; have 'int'" } + +void fvi_vp (Type, void*); // { dg-message "declared here" } +A (fvi_vp) void* alloc_fvi_vp (int); // { dg-error "'malloc' attribute argument 1 must take a pointer type as its first argument; have 'Type'" } + + +void fpv (void*); +A (fpv) void* alloc_fpv (int); + +void fpv_i (void*, int); +A (fpv_i) void* alloc_fpv_i (int); + +void fpv_pv (void*, void*); +A (fpv_i) void* alloc_fpv_pv (int); + + +void gpc (char*); +void hpi (int*); +A (fpv) A (gpc) A (hpi) Type* alloc_fpv_gpv (int); + + +/* Verify that the attribute can be applied to <stdio.h> functions. */ +typedef struct FILE FILE; +typedef __SIZE_TYPE__ size_t; + +int fclose (FILE*); +FILE* fdopen (int); +FILE* fopen (const char*, const char*); +FILE* freopen (const char*, const char*, FILE*); +int pclose (FILE*); +FILE* popen (const char*, const char*); +FILE* tmpfile (void); + +A (fclose) A (freopen, 3) A (pclose) + FILE* fdopen (int); +A (fclose) A (freopen, 3) A (pclose) + FILE* fopen (const char*, const char*); +A (fclose) A (freopen, 3) A (pclose) + FILE* fmemopen(void *, size_t, const char *); +A (fclose) A (freopen, 3) A (pclose) + FILE* freopen (const char*, const char*, FILE*); +A (fclose) A (freopen, 3) A (pclose) + FILE* popen (const char*, const char*); +A (fclose) A (freopen, 3) A (pclose) + FILE* tmpfile (void); diff --git a/gcc/testsuite/gcc.dg/free-1.c b/gcc/testsuite/gcc.dg/free-1.c index 5496c84..ad49d78 100644 --- a/gcc/testsuite/gcc.dg/free-1.c +++ b/gcc/testsuite/gcc.dg/free-1.c @@ -13,14 +13,14 @@ void foo (void) static char buf4[10], e; char *q = buf; free (p); - free (q); /* { dg-warning "attempt to free a non-heap object" } */ - free (buf2); /* { dg-warning "attempt to free a non-heap object" } */ - free (&c); /* { dg-warning "attempt to free a non-heap object" } */ - free (buf3); /* { dg-warning "attempt to free a non-heap object" } */ - free (&d); /* { dg-warning "attempt to free a non-heap object" } */ - free (buf4); /* { dg-warning "attempt to free a non-heap object" } */ - free (&e); /* { dg-warning "attempt to free a non-heap object" } */ + free (q); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (buf2); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (&c); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (buf3); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (&d); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (buf4); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (&e); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ free (&r->a); - free ("abcd"); /* { dg-warning "attempt to free a non-heap object" } */ - free (L"abcd"); /* { dg-warning "attempt to free a non-heap object" } */ + free ("abcd"); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (L"abcd"); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ } diff --git a/gcc/testsuite/gcc.dg/free-2.c b/gcc/testsuite/gcc.dg/free-2.c index eb94651..edbcdc7 100644 --- a/gcc/testsuite/gcc.dg/free-2.c +++ b/gcc/testsuite/gcc.dg/free-2.c @@ -13,14 +13,14 @@ void foo (void) static char buf4[10], e; char *q = buf; free (p); - free (q); /* At -O0 no warning is reported here. */ - free (buf2); /* { dg-warning "attempt to free a non-heap object" } */ - free (&c); /* { dg-warning "attempt to free a non-heap object" } */ - free (buf3); /* { dg-warning "attempt to free a non-heap object" } */ - free (&d); /* { dg-warning "attempt to free a non-heap object" } */ - free (buf4); /* { dg-warning "attempt to free a non-heap object" } */ - free (&e); /* { dg-warning "attempt to free a non-heap object" } */ + free (q); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (buf2); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (&c); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (buf3); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (&d); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (buf4); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (&e); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ free (&r->a); - free ("abcd"); /* { dg-warning "attempt to free a non-heap object" } */ - free (L"abcd"); /* { dg-warning "attempt to free a non-heap object" } */ + free ("abcd"); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ + free (L"abcd"); /* { dg-warning "\\\[-Wfree-nonheap-object" } */ } diff --git a/gcc/testsuite/gcc.dg/pr98099.c b/gcc/testsuite/gcc.dg/pr98099.c index 34909f2..12e52f2 100644 --- a/gcc/testsuite/gcc.dg/pr98099.c +++ b/gcc/testsuite/gcc.dg/pr98099.c @@ -1,7 +1,7 @@ /* PR middle-end/98099 */ /* Reported by G. Steinmetz <gscfq@t-online.de> */ -/* { dg-do compile } */ +/* { dg-do compile { target dfp } } */ /* { dg-options "-fsso-struct=big-endian" } */ struct S { _Decimal128 a; }; diff --git a/gcc/testsuite/gcc.dg/torture/pr71816.c b/gcc/testsuite/gcc.dg/torture/pr71816.c index be37ad9..cc143fa 100644 --- a/gcc/testsuite/gcc.dg/torture/pr71816.c +++ b/gcc/testsuite/gcc.dg/torture/pr71816.c @@ -20,3 +20,7 @@ struct ext2_icount_el *insert_icount_el() { ext2fs_resize_mem(&insert_icount_el_icount_1); return 0; } + +/* Passing the address of a declared object to realloc triggers + -Wfree-nonheap-object unless -flto is used. + { dg-prune-output "\\\[-Wfree-nonheap-object" } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-4.c b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-4.c index 6a03588..e6dd4be 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-4.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized" } */ +/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized --param case-values-threshold=5" } */ int global; int foo (); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-6.c b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-6.c index 464b1fb..b164067 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-6.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized" } */ +/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized --param case-values-threshold=5" } */ int global; int foo (); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-8.c b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-8.c index f43ce7d..f4d06fe 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-8.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-8.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized" } */ +/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized --param case-values-threshold=5" } */ int global; int global1; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c index 55b4fd0..df4120d 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c @@ -5,7 +5,7 @@ void test1(void) { int *p = __builtin_malloc (sizeof (int) * 4); *p++ = 4; - __builtin_free (p); + __builtin_free (p); // { dg-warning "\\\[-Wfree-nonheap-object" } } /* Undefined. We can't do anything here. */ diff --git a/gcc/testsuite/gcc.target/i386/pr96226.c b/gcc/testsuite/gcc.target/i386/pr96226.c new file mode 100644 index 0000000..cc010fa --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr96226.c @@ -0,0 +1,16 @@ +/* PR target/96226 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "\troll\t" 4 } } */ +/* { dg-final { scan-assembler-times "\trolq\t" 4 { target { ! ia32 } } } } */ + +int f1 (int x) { return ~(1U << (x & 0x1f)); } +int f2 (int x) { return ~(1U << x); } +int f3 (unsigned char *x) { return ~(1U << (x[0] & 0x1f)); } +int f4 (unsigned char *x) { return ~(1U << x[0]); } +#ifdef __x86_64__ +long int f5 (int x) { return ~(1ULL << (x & 0x3f)); } +long int f6 (int x) { return ~(1ULL << x); } +long int f7 (unsigned char *x) { return ~(1ULL << (x[0] & 0x3f)); } +long int f8 (unsigned char *x) { return ~(1ULL << x[0]); } +#endif diff --git a/gcc/testsuite/gcc.target/i386/pr98100.c b/gcc/testsuite/gcc.target/i386/pr98100.c new file mode 100644 index 0000000..4deda1a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98100.c @@ -0,0 +1,9 @@ +/* PR target/98100 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-avx -fvar-tracking-assignments -g0" } */ + +__attribute__((target_clones("default","avx2"))) void +foo () +{ + __attribute__((__vector_size__(8 * sizeof(int)))) int b = {}; +} diff --git a/gcc/testsuite/gnat.dg/opt91.adb b/gcc/testsuite/gnat.dg/opt91.adb new file mode 100644 index 0000000..b0132f8 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt91.adb @@ -0,0 +1,11 @@ +-- { dg-do compile } +-- { dg-options "-O2 -fchecking=1" } + +package body Opt91 is + + function Custom_Image (Self : True_Relation_Rec) return String is + begin + return "<True>"; + end; + +end Opt91; diff --git a/gcc/testsuite/gnat.dg/opt91.ads b/gcc/testsuite/gnat.dg/opt91.ads new file mode 100644 index 0000000..b31aa8d --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt91.ads @@ -0,0 +1,10 @@ +with Opt91_Pkg; use Opt91_Pkg; + +package Opt91 is + + type True_Relation_Rec is null record; + function Custom_Image (Self : True_Relation_Rec) return String; + + package True_Relation is new Pure_Relation (Ty => True_Relation_Rec); + +end Opt91; diff --git a/gcc/testsuite/gnat.dg/opt91_pkg.adb b/gcc/testsuite/gnat.dg/opt91_pkg.adb new file mode 100644 index 0000000..5b95fb2e --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt91_pkg.adb @@ -0,0 +1,12 @@ +package body Opt91_Pkg is + + package body Pure_Relation is + + overriding function Custom_Image (Self : Rel) return String is + begin + return Custom_Image (Self.Rel); + end Custom_Image; + + end Pure_Relation; + +end Opt91_Pkg; diff --git a/gcc/testsuite/gnat.dg/opt91_pkg.ads b/gcc/testsuite/gnat.dg/opt91_pkg.ads new file mode 100644 index 0000000..9bfd0f0 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt91_pkg.ads @@ -0,0 +1,19 @@ +package Opt91_Pkg is + + type Base_Relation is abstract tagged null record; + + function Custom_Image (Self : Base_Relation) return String is abstract; + + generic + type Ty is private; + with function Custom_Image (Self : Ty) return String is <>; + package Pure_Relation is + + type Rel is new Base_Relation with record + Rel : Ty; + end record; + + overriding function Custom_Image (Self : Rel) return String; + end Pure_Relation; + +end Opt91_Pkg; diff --git a/gcc/toplev.c b/gcc/toplev.c index cb4ae77..93a4194 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -116,9 +116,6 @@ static void compile_file (void); /* True if we don't need a backend (e.g. preprocessing only). */ static bool no_backend; -/* Length of line when printing switch values. */ -#define MAX_LINE 75 - /* Decoded options, and number of such options. */ struct cl_decoded_option *save_decoded_options; unsigned int save_decoded_options_count; @@ -687,148 +684,7 @@ print_version (FILE *file, const char *indent, bool show_global_state) } } -static int -print_to_asm_out_file (print_switch_type type, const char * text) -{ - bool prepend_sep = true; - - switch (type) - { - case SWITCH_TYPE_LINE_END: - putc ('\n', asm_out_file); - return 1; - - case SWITCH_TYPE_LINE_START: - fputs (ASM_COMMENT_START, asm_out_file); - return strlen (ASM_COMMENT_START); - - case SWITCH_TYPE_DESCRIPTIVE: - if (ASM_COMMENT_START[0] == 0) - prepend_sep = false; - /* FALLTHRU */ - case SWITCH_TYPE_PASSED: - case SWITCH_TYPE_ENABLED: - if (prepend_sep) - fputc (' ', asm_out_file); - fputs (text, asm_out_file); - /* No need to return the length here as - print_single_switch has already done it. */ - return 0; - - default: - return -1; - } -} - -static int -print_to_stderr (print_switch_type type, const char * text) -{ - switch (type) - { - case SWITCH_TYPE_LINE_END: - putc ('\n', stderr); - return 1; - - case SWITCH_TYPE_LINE_START: - return 0; - - case SWITCH_TYPE_PASSED: - case SWITCH_TYPE_ENABLED: - fputc (' ', stderr); - /* FALLTHRU */ - - case SWITCH_TYPE_DESCRIPTIVE: - fputs (text, stderr); - /* No need to return the length here as - print_single_switch has already done it. */ - return 0; - - default: - return -1; - } -} - -/* Print an option value and return the adjusted position in the line. - ??? print_fn doesn't handle errors, eg disk full; presumably other - code will catch a disk full though. */ - -static int -print_single_switch (print_switch_fn_type print_fn, - int pos, - print_switch_type type, - const char * text) -{ - /* The ultrix fprintf returns 0 on success, so compute the result - we want here since we need it for the following test. The +1 - is for the separator character that will probably be emitted. */ - int len = strlen (text) + 1; - - if (pos != 0 - && pos + len > MAX_LINE) - { - print_fn (SWITCH_TYPE_LINE_END, NULL); - pos = 0; - } - - if (pos == 0) - pos += print_fn (SWITCH_TYPE_LINE_START, NULL); - - print_fn (type, text); - return pos + len; -} - -/* Print active target switches using PRINT_FN. - POS is the current cursor position and MAX is the size of a "line". - Each line begins with INDENT and ends with TERM. - Each switch is separated from the next by SEP. */ -static void -print_switch_values (print_switch_fn_type print_fn) -{ - int pos = 0; - size_t j; - - /* Print the options as passed. */ - pos = print_single_switch (print_fn, pos, - SWITCH_TYPE_DESCRIPTIVE, _("options passed: ")); - - for (j = 1; j < save_decoded_options_count; j++) - { - switch (save_decoded_options[j].opt_index) - { - case OPT_o: - case OPT_d: - case OPT_dumpbase: - case OPT_dumpbase_ext: - case OPT_dumpdir: - case OPT_quiet: - case OPT_version: - /* Ignore these. */ - continue; - } - - pos = print_single_switch (print_fn, pos, SWITCH_TYPE_PASSED, - save_decoded_options[j].orig_option_with_args_text); - } - - if (pos > 0) - print_fn (SWITCH_TYPE_LINE_END, NULL); - - /* Print the -f and -m options that have been enabled. - We don't handle language specific options but printing argv - should suffice. */ - pos = print_single_switch (print_fn, 0, - SWITCH_TYPE_DESCRIPTIVE, _("options enabled: ")); - - unsigned lang_mask = lang_hooks.option_lang_mask (); - for (j = 0; j < cl_options_count; j++) - if (cl_options[j].cl_report - && option_enabled (j, lang_mask, &global_options) > 0) - pos = print_single_switch (print_fn, pos, - SWITCH_TYPE_ENABLED, cl_options[j].opt_text); - - print_fn (SWITCH_TYPE_LINE_END, NULL); -} /* Open assembly code output file. Do this even if -fsyntax-only is on, because then the driver will have provided the name of a @@ -875,14 +731,11 @@ init_asm_output (const char *name) { if (targetm.asm_out.record_gcc_switches) { - /* Let the target know that we are about to start recording. */ - targetm.asm_out.record_gcc_switches (SWITCH_TYPE_DESCRIPTIVE, - NULL); - /* Now record the switches. */ - print_switch_values (targetm.asm_out.record_gcc_switches); - /* Let the target know that the recording is over. */ - targetm.asm_out.record_gcc_switches (SWITCH_TYPE_DESCRIPTIVE, - NULL); + const char *str + = gen_producer_string (lang_hooks.name, + save_decoded_options, + save_decoded_options_count); + targetm.asm_out.record_gcc_switches (str); } else inform (UNKNOWN_LOCATION, @@ -892,11 +745,13 @@ init_asm_output (const char *name) if (flag_verbose_asm) { - /* Print the list of switches in effect - into the assembler file as comments. */ print_version (asm_out_file, ASM_COMMENT_START, true); - print_switch_values (print_to_asm_out_file); - putc ('\n', asm_out_file); + fputs (ASM_COMMENT_START, asm_out_file); + fputs (" options passed: ", asm_out_file); + fputs (gen_command_line_string (save_decoded_options, + save_decoded_options_count), + asm_out_file); + fputc ('\n', asm_out_file); } } } @@ -1526,8 +1381,13 @@ process_options (void) if (version_flag) { print_version (stderr, "", true); - if (! quiet_flag) - print_switch_values (print_to_stderr); + if (!quiet_flag) + { + fputs ("options passed: ", stderr); + fputs (gen_command_line_string (save_decoded_options, + save_decoded_options_count), stderr); + fputc ('\n', stderr); + } } if (flag_syntax_only) @@ -2185,7 +2185,7 @@ build_constructor_from_vec (tree type, const vec<tree, va_gc> *vals) { vec<constructor_elt, va_gc> *v = NULL; - for (tree t : *vals) + for (tree t : vals) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t); return build_constructor (type, v); diff --git a/gcc/varasm.c b/gcc/varasm.c index 961d2d6..0fac368 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "stor-layout.h" #include "varasm.h" +#include "version.h" #include "flags.h" #include "stmt.h" #include "expr.h" @@ -58,6 +59,8 @@ along with GCC; see the file COPYING3. If not see #include "rtl-iter.h" #include "file-prefix-map.h" /* remap_debug_filename() */ #include "alloc-pool.h" +#include "toplev.h" +#include "opts.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data declarations. */ @@ -8053,45 +8056,14 @@ output_object_blocks (void) we want to emit NUL strings terminators into the object file we have to use ASM_OUTPUT_SKIP. */ -int -elf_record_gcc_switches (print_switch_type type, const char * name) +void +elf_record_gcc_switches (const char *options) { - switch (type) - { - case SWITCH_TYPE_PASSED: - ASM_OUTPUT_ASCII (asm_out_file, name, strlen (name)); - ASM_OUTPUT_SKIP (asm_out_file, HOST_WIDE_INT_1U); - break; - - case SWITCH_TYPE_DESCRIPTIVE: - if (name == NULL) - { - /* Distinguish between invocations where name is NULL. */ - static bool started = false; - - if (!started) - { - section * sec; - - sec = get_section (targetm.asm_out.record_gcc_switches_section, - SECTION_DEBUG - | SECTION_MERGE - | SECTION_STRINGS - | (SECTION_ENTSIZE & 1), - NULL); - switch_to_section (sec); - started = true; - } - } - - default: - break; - } - - /* The return value is currently ignored by the caller, but must be 0. - For -fverbose-asm the return value would be the number of characters - emitted into the assembler file. */ - return 0; + section *sec = get_section (targetm.asm_out.record_gcc_switches_section, + SECTION_DEBUG | SECTION_MERGE + | SECTION_STRINGS | (SECTION_ENTSIZE & 1), NULL); + switch_to_section (sec); + ASM_OUTPUT_ASCII (asm_out_file, options, strlen (options) + 1); } /* Emit text to declare externally defined symbols. It is needed to @@ -419,6 +419,16 @@ struct GTY((user)) vec { }; +/* Allow C++11 range-based 'for' to work directly on vec<T>*. */ +template<typename T, typename A, typename L> +T* begin (vec<T,A,L> *v) { return v ? v->begin () : nullptr; } +template<typename T, typename A, typename L> +T* end (vec<T,A,L> *v) { return v ? v->end () : nullptr; } +template<typename T, typename A, typename L> +const T* begin (const vec<T,A,L> *v) { return v ? v->begin () : nullptr; } +template<typename T, typename A, typename L> +const T* end (const vec<T,A,L> *v) { return v ? v->end () : nullptr; } + /* Generic vec<> debug helpers. These need to be instantiated for each vec<TYPE> used throughout diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 20b77fd..9b95f55 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,21 @@ +2020-12-03 Michael Meissner <meissner@linux.ibm.com> + + PR libgcc/97543 + PR libgcc/97643 + * config/rs6000/t-linux (IBM128_STATIC_OBJS): New make variable. + (IBM128_SHARED_OBJS): New make variable. + (IBM128_OBJS): New make variable. Set all objects to use the + explicit IBM format, and disable gnu attributes. + (IBM128_CFLAGS): New make variable. + (gcc_s_compile): Add -mno-gnu-attribute to all shared library + modules. + +2020-12-03 Alexandre Oliva <oliva@adacore.com> + + * config/t-vxworks (LIB2ADD): Drop. + * config/t-vxworks7 (LIB2ADD): Likewise. + * config/vxcache.c: Remove. + 2020-11-30 Stefan Kanthak <stefan.kanthak@nexgo.de> * libgcc2.c (bswapsi2): Make constants unsigned. diff --git a/libgo/runtime/go-fieldtrack.c b/libgo/runtime/go-fieldtrack.c index 22f091b..80be27c 100644 --- a/libgo/runtime/go-fieldtrack.c +++ b/libgo/runtime/go-fieldtrack.c @@ -31,7 +31,7 @@ extern void *mapassign (const struct maptype *, void *hmap, const void *key) // The type descriptor for map[string] bool. */ extern const char map_string_bool[] __attribute__ ((weak)); extern const char map_string_bool[] - __asm__ (GOSYM_PREFIX "type..map.6string.7bool"); + __asm__ (GOSYM_PREFIX "type..map_6string_7bool"); void runtime_Fieldtrack (void *) __asm__ (GOSYM_PREFIX "runtime.Fieldtrack"); diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 6b1c345..ed9c82c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,57 @@ +2020-12-03 Martin Sebor <msebor@redhat.com> + + * testsuite/ext/vstring/modifiers/clear/56166.cc: Suppress a false + positive warning. + +2020-12-03 Jonathan Wakely <jwakely@redhat.com> + + * testsuite/26_numerics/bit/bit.cast/bit_cast.cc: Remove stray + word from copy&paste. + * testsuite/26_numerics/bit/bit.cast/version.cc: Likewise. + +2020-12-03 Jonathan Wakely <jwakely@redhat.com> + + * doc/xml/manual/status_cxx2020.xml: Update C++20 status. + * doc/html/*: Regenerate. + +2020-12-03 JeanHeyd Meneide <phdofthehouse@gmail.com> + + * doc/doxygen/user.cfg.in (INPUT): Add <source_location>. + * include/Makefile.am: Add <source_location>. + * include/Makefile.in: Regenerate. + * include/std/version (__cpp_lib_source_location): Define. + * include/std/source_location: New file. + * testsuite/18_support/source_location/1.cc: New test. + * testsuite/18_support/source_location/consteval.cc: New test. + * testsuite/18_support/source_location/srcloc.h: New test. + * testsuite/18_support/source_location/version.cc: New test. + +2020-12-03 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/93121 + * include/std/bit (__cpp_lib_bit_cast, bit_cast): Define. + * include/std/version (__cpp_lib_bit_cast): Define. + * testsuite/26_numerics/bit/bit.cast/bit_cast.cc: New test. + * testsuite/26_numerics/bit/bit.cast/version.cc: New test. + +2020-12-03 Jonathan Wakely <jwakely@redhat.com> + + * config/abi/post/powerpc-linux-gnu/baseline_symbols.txt: + Update. + * config/abi/post/powerpc64-linux-gnu/32/baseline_symbols.txt: + Update. + +2020-12-03 Jonathan Wakely <jwakely@redhat.com> + + * include/std/array (array::operator[](size_t) const, array::front() const) + (array::back() const) [__cplusplus == 201103]: Disable + assertions. + * testsuite/23_containers/array/element_access/constexpr_element_access.cc: + Check for correct values. + * testsuite/23_containers/array/tuple_interface/get_neg.cc: + Adjust dg-error line numbers. + * testsuite/23_containers/array/debug/constexpr_c++11.cc: New test. + 2020-12-02 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/65480 diff --git a/libstdc++-v3/testsuite/18_support/source_location/1.cc b/libstdc++-v3/testsuite/18_support/source_location/1.cc index c945aaa..c9cb743 100644 --- a/libstdc++-v3/testsuite/18_support/source_location/1.cc +++ b/libstdc++-v3/testsuite/18_support/source_location/1.cc @@ -89,7 +89,7 @@ int main () VERIFY(main_sl.line() == main_sl_line); // closing paren of call VERIFY(main_sl.column() == 64); - VERIFY(main_sl_fn_name.ends_with("main"sv)); + VERIFY(main_sl_fn_name.ends_with("main()"sv)); VERIFY(main_sl_fi_name.ends_with("1.cc"sv)); std::string_view f_arg_sl_fn_name(f_arg_sl.function_name()); @@ -97,28 +97,28 @@ int main () VERIFY(f_arg_sl.line() == f_arg_sl_line); // closing paren of call VERIFY(f_arg_sl.column() == 64); - VERIFY(f_arg_sl_fn_name.ends_with("main"sv)); + VERIFY(f_arg_sl_fn_name.ends_with("main()"sv)); VERIFY(f_arg_sl_fi_name.ends_with("1.cc"sv)); std::string_view g_sl_fn_name(g_sl.function_name()); std::string_view g_sl_fi_name(g_sl.file_name()); VERIFY(g_sl.line() == g_sl_line); VERIFY(g_sl.column() == 58); // closing paren of call - VERIFY(g_sl_fn_name.ends_with("g"sv)); + VERIFY(g_sl_fn_name.ends_with("g()"sv)); VERIFY(g_sl_fi_name.ends_with("1.cc"sv)); std::string_view h_sl_fn_name(h_sl.function_name()); std::string_view h_sl_fi_name(h_sl.file_name()); VERIFY(h_sl.line() == 23); VERIFY(h_sl.column() == 58); // closing paren of call - VERIFY(h_sl_fn_name.ends_with("h"sv)); + VERIFY(h_sl_fn_name.ends_with("h()"sv)); VERIFY(h_sl_fi_name.ends_with("srcloc.h"sv)); std::string_view member_main_sl_fn_name(member_main_sl.member.function_name()); std::string_view member_main_sl_fi_name(member_main_sl.member.file_name()); VERIFY(member_main_sl.member.line() == main_sl_line); VERIFY(member_main_sl.member.column() == 64); - VERIFY(member_main_sl_fn_name.ends_with("main"sv)); + VERIFY(member_main_sl_fn_name.ends_with("main()"sv)); VERIFY(member_main_sl_fi_name.ends_with("1.cc"sv)); std::string_view member_defaulted_sl_fi_name( @@ -128,9 +128,7 @@ int main () VERIFY(member_defaulted_sl.member.line() == 46); // closing paren of constructor declaration VERIFY(member_defaulted_sl.member.column() == 25); -#if 0 VERIFY(member_defaulted_sl_fn_name.starts_with("s::s(int)"sv)); -#endif VERIFY(member_defaulted_sl_fi_name.ends_with("1.cc"sv)); std::string_view member_sl_fi_name( @@ -140,7 +138,7 @@ int main () VERIFY(member_sl.member.line() == member_sl_line); // closing brace/paren of constructor VERIFY(member_sl.member.column() == 19); - VERIFY(member_sl_fn_name.starts_with("main"sv)); + VERIFY(member_sl_fn_name.starts_with("int main()"sv)); VERIFY(member_sl_fi_name.ends_with("1.cc"sv)); std::string_view f_sl_fi_name(f_sl.file_name()); @@ -148,7 +146,7 @@ int main () VERIFY(f_sl.line() == f_sl_line); // closing paren of call VERIFY(f_sl.column() == 33); - VERIFY(f_sl_fn_name.ends_with("main"sv)); + VERIFY(f_sl_fn_name.ends_with("main()"sv)); VERIFY(f_sl_fi_name.ends_with("1.cc"sv)); return 0; diff --git a/libstdc++-v3/testsuite/18_support/source_location/consteval.cc b/libstdc++-v3/testsuite/18_support/source_location/consteval.cc index 9b137f8..51c8fb2 100644 --- a/libstdc++-v3/testsuite/18_support/source_location/consteval.cc +++ b/libstdc++-v3/testsuite/18_support/source_location/consteval.cc @@ -83,7 +83,7 @@ int main () static_assert(main_sl.line() == main_sl_line); // closing paren of call static_assert(main_sl.column() == 74); - static_assert(main_sl_fn_name.ends_with("main"sv)); + static_assert(main_sl_fn_name.ends_with("main()"sv)); static_assert(main_sl_fi_name.ends_with("consteval.cc"sv)); constexpr std::string_view f_arg_sl_fn_name(f_arg_sl.function_name()); @@ -91,28 +91,28 @@ int main () static_assert(f_arg_sl.line() == f_arg_sl_line); // closing paren of call static_assert(f_arg_sl.column() == 74); - static_assert(f_arg_sl_fn_name.ends_with("main"sv)); + static_assert(f_arg_sl_fn_name.ends_with("main()"sv)); static_assert(f_arg_sl_fi_name.ends_with("consteval.cc"sv)); constexpr std::string_view g_sl_fn_name(g_sl.function_name()); constexpr std::string_view g_sl_fi_name(g_sl.file_name()); static_assert(g_sl.line() == g_sl_line); static_assert(g_sl.column() == 58); // closing paren of call - static_assert(g_sl_fn_name.ends_with("g"sv)); + static_assert(g_sl_fn_name.ends_with("g()"sv)); static_assert(g_sl_fi_name.ends_with("consteval.cc"sv)); constexpr std::string_view h_sl_fn_name(h_sl.function_name()); constexpr std::string_view h_sl_fi_name(h_sl.file_name()); static_assert(h_sl.line() == 23); static_assert(h_sl.column() == 58); // closing paren of call - static_assert(h_sl_fn_name.ends_with("h"sv)); + static_assert(h_sl_fn_name.ends_with("h()"sv)); static_assert(h_sl_fi_name.ends_with("srcloc.h"sv)); constexpr std::string_view member_main_sl_fn_name(member_main_sl.member.function_name()); constexpr std::string_view member_main_sl_fi_name(member_main_sl.member.file_name()); static_assert(member_main_sl.member.line() == main_sl_line); static_assert(member_main_sl.member.column() == 74); - static_assert(member_main_sl_fn_name.ends_with("main"sv)); + static_assert(member_main_sl_fn_name.ends_with("main()"sv)); static_assert(member_main_sl_fi_name.ends_with("consteval.cc"sv)); constexpr std::string_view member_defaulted_sl_fi_name( @@ -122,9 +122,7 @@ int main () static_assert(member_defaulted_sl.member.line() == 36); // closing paren of constructor declaration static_assert(member_defaulted_sl.member.column() == 25); -#if 0 static_assert(member_defaulted_sl_fn_name.ends_with("s::s(int)"sv)); -#endif static_assert(member_defaulted_sl_fi_name.ends_with("consteval.cc"sv)); constexpr std::string_view member_sl_fi_name( @@ -134,7 +132,7 @@ int main () static_assert(member_sl.member.line() == member_sl_line); // closing brace/paren of constructor static_assert(member_sl.member.column() == 29); - static_assert(member_sl_fn_name.starts_with("main"sv)); + static_assert(member_sl_fn_name.starts_with("int main()"sv)); static_assert(member_sl_fi_name.ends_with("consteval.cc"sv)); constexpr std::string_view f_sl_fi_name(f_sl.file_name()); @@ -142,7 +140,7 @@ int main () static_assert(f_sl.line() == f_sl_line); // closing paren of call static_assert(f_sl.column() == 43); - static_assert(f_sl_fn_name.ends_with("main"sv)); + static_assert(f_sl_fn_name.ends_with("main()"sv)); static_assert(f_sl_fi_name.ends_with("consteval.cc"sv)); return 0; diff --git a/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc b/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc index 84dd79e..b5ce78d 100644 --- a/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc +++ b/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc @@ -56,12 +56,12 @@ template<typename T> throw std::bad_alloc(); } } - return (T*)new char[n * sizeof(T)]; + return (T*)operator new (n * sizeof(T)); } void deallocate(T* p, size_type) { - delete[] (char*)p; + operator delete (p); } }; @@ -94,3 +94,7 @@ int main() } } } + +// The __versa_string destructor triggers a bogus -Wfree-nonheap-object +// due to pr54202. +// { dg-prune-output "\\\[-Wfree-nonheap-object" } |