mirror of git://gcc.gnu.org/git/gcc.git
Merge commit 'a945c346f57ba40fc80c14ac59be0d43624e559d^' into HEAD
This commit is contained in:
commit
884c2b766e
18
ChangeLog
18
ChangeLog
|
|
@ -1,3 +1,21 @@
|
|||
2023-12-30 Joseph Myers <jsm@polyomino.org.uk>
|
||||
|
||||
* MAINTAINERS: Update my email address.
|
||||
|
||||
2023-12-14 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
|
||||
Thomas Schwinge <thomas@codesourcery.com>
|
||||
|
||||
* Makefile.def: Add libgrust as host & target module.
|
||||
* configure.ac: Add libgrust to host tools list. Add libgrust to
|
||||
noconfigdirs if we're not building target libstdc++.
|
||||
* Makefile.in: Regenerate.
|
||||
* configure: Regenerate.
|
||||
|
||||
2023-12-14 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
|
||||
Arthur Cohen <arthur.cohen@embecosm.com>
|
||||
|
||||
* MAINTAINERS: Add maintainers for libgrust.
|
||||
|
||||
2023-12-13 Arsen Arsenović <arsen@aarsen.me>
|
||||
|
||||
* Makefile.def (gettext): Disable (via missing)
|
||||
|
|
|
|||
16
MAINTAINERS
16
MAINTAINERS
|
|
@ -34,7 +34,7 @@ Jeff Law <jlaw@ventanamicro.com>
|
|||
Michael Meissner <gnu@the-meissners.org>
|
||||
Jason Merrill <jason@redhat.com>
|
||||
David S. Miller <davem@redhat.com>
|
||||
Joseph Myers <joseph@codesourcery.com>
|
||||
Joseph Myers <jsm@polyomino.org.uk>
|
||||
Richard Sandiford <richard.sandiford@arm.com>
|
||||
Bernd Schmidt <bernds_cb1@t-online.de>
|
||||
Ian Lance Taylor <ian@airs.com>
|
||||
|
|
@ -155,7 +155,7 @@ cygwin, mingw-w64 Jonathan Yong <10walls@gmail.com>
|
|||
|
||||
Language Front Ends Maintainers
|
||||
|
||||
C front end/ISO C99 Joseph Myers <joseph@codesourcery.com>
|
||||
C front end/ISO C99 Joseph Myers <jsm@polyomino.org.uk>
|
||||
Ada front end Arnaud Charlet <charlet@adacore.com>
|
||||
Ada front end Eric Botcazou <ebotcazou@libertysurf.fr>
|
||||
Ada front end Marc Poulhiès <poulhies@adacore.com>
|
||||
|
|
@ -192,7 +192,7 @@ libquadmath Jakub Jelinek <jakub@redhat.com>
|
|||
libvtv Caroline Tice <cmtice@google.com>
|
||||
libphobos Iain Buclaw <ibuclaw@gdcproject.org>
|
||||
line map Dodji Seketeli <dodji@redhat.com>
|
||||
soft-fp Joseph Myers <joseph@codesourcery.com>
|
||||
soft-fp Joseph Myers <jsm@polyomino.org.uk>
|
||||
scheduler (+ haifa) Jim Wilson <wilson@tuliptree.org>
|
||||
scheduler (+ haifa) Michael Meissner <gnu@the-meissners.org>
|
||||
scheduler (+ haifa) Jeff Law <jeffreyalaw@gmail.com>
|
||||
|
|
@ -219,7 +219,7 @@ jump.cc David S. Miller <davem@redhat.com>
|
|||
web pages Gerald Pfeifer <gerald@pfeifer.com>
|
||||
config.sub/config.guess Ben Elliston <config-patches@gnu.org>
|
||||
i18n Philipp Thomas <pth@suse.de>
|
||||
i18n Joseph Myers <joseph@codesourcery.com>
|
||||
i18n Joseph Myers <jsm@polyomino.org.uk>
|
||||
diagnostic messages Dodji Seketeli <dodji@redhat.com>
|
||||
diagnostic messages David Malcolm <dmalcolm@redhat.com>
|
||||
build machinery (*.in) Paolo Bonzini <bonzini@gnu.org>
|
||||
|
|
@ -227,14 +227,14 @@ build machinery (*.in) Nathanael Nerode <neroden@gcc.gnu.org>
|
|||
build machinery (*.in) Alexandre Oliva <aoliva@gcc.gnu.org>
|
||||
build machinery (*.in) Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
docs co-maintainer Gerald Pfeifer <gerald@pfeifer.com>
|
||||
docs co-maintainer Joseph Myers <joseph@codesourcery.com>
|
||||
docs co-maintainer Joseph Myers <jsm@polyomino.org.uk>
|
||||
docs co-maintainer Sandra Loosemore <sandra@codesourcery.com>
|
||||
docstring relicensing Gerald Pfeifer <gerald@pfeifer.com>
|
||||
docstring relicensing Joseph Myers <joseph@codesourcery.com>
|
||||
docstring relicensing Joseph Myers <jsm@polyomino.org.uk>
|
||||
predict.def Jan Hubicka <hubicka@ucw.cz>
|
||||
gcov Jan Hubicka <hubicka@ucw.cz>
|
||||
gcov Nathan Sidwell <nathan@acm.org>
|
||||
option handling Joseph Myers <joseph@codesourcery.com>
|
||||
option handling Joseph Myers <jsm@polyomino.org.uk>
|
||||
middle-end Jeff Law <jeffreyalaw@gmail.com>
|
||||
middle-end Ian Lance Taylor <ian@airs.com>
|
||||
middle-end Richard Biener <rguenther@suse.de>
|
||||
|
|
@ -278,7 +278,7 @@ CTF, BTF, bpf port David Faust <david.faust@oracle.com>
|
|||
dataflow Paolo Bonzini <bonzini@gnu.org>
|
||||
dataflow Seongbae Park <seongbae.park@gmail.com>
|
||||
dataflow Kenneth Zadeck <zadeck@naturalbridge.com>
|
||||
driver Joseph Myers <joseph@codesourcery.com>
|
||||
driver Joseph Myers <jsm@polyomino.org.uk>
|
||||
Fortran Harald Anlauf <anlauf@gmx.de>
|
||||
Fortran Janne Blomqvist <jb@gcc.gnu.org>
|
||||
Fortran Tobias Burnus <tobias@codesourcery.com>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@
|
|||
* server.cc: New.
|
||||
|
||||
|
||||
Copyright (C) 2020-2023 Free Software Foundation, Inc.
|
||||
Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
|
|
|
|||
|
|
@ -1,3 +1,22 @@
|
|||
2023-12-21 Alexandre Oliva <oliva@adacore.com>
|
||||
|
||||
* compare_tests: Add tool to test lines. Match tabs besides
|
||||
blanks to insert tool and target. Don't print undefined fname.
|
||||
|
||||
2023-12-20 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* gcc-git-customization.sh: Add git gcc-style alias.
|
||||
|
||||
2023-12-14 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
|
||||
Arthur Cohen <arthur.cohen@embecosm.com>
|
||||
|
||||
* gcc_update: Add libgrust file dependencies.
|
||||
|
||||
2023-12-14 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
|
||||
Arthur Cohen <arthur.cohen@embecosm.com>
|
||||
|
||||
* gcc-changelog/git_commit.py: Add libgrust.
|
||||
|
||||
2023-12-13 Arsen Arsenović <arsen@aarsen.me>
|
||||
|
||||
* download_prerequisites
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ if [ -d "$1" -a -d "$2" ] ; then
|
|||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
exit_status=`expr $exit_status + 1`
|
||||
echo "## Differences found: $fname"
|
||||
echo "## Differences found"
|
||||
fi
|
||||
if [ $exit_status -ne 0 ]; then
|
||||
echo "# $exit_status differences in $cmnsums common sum files found"
|
||||
|
|
@ -108,8 +108,8 @@ elif [ -d "$1" -o -d "$2" ] ; then
|
|||
usage "Must specify either two directories or two files"
|
||||
fi
|
||||
|
||||
sed 's/^XFAIL/FAIL/; s/^ERROR/FAIL/; s/^XPASS/PASS/' < "$1" | awk '/^Running target / {target = $3} { if (target != "unix") { sub(/: /, "&"target": " ); }; print $0; }' | cut -c1-2000 >$tmp1
|
||||
sed 's/^XFAIL/FAIL/; s/^ERROR/FAIL/; s/^XPASS/PASS/' < "$2" | awk '/^Running target / {target = $3} { if (target != "unix") { sub(/: /, "&"target": " ); }; print $0; }' | cut -c1-2000 >$tmp2
|
||||
sed 's/^XFAIL/FAIL/; s/^ERROR/FAIL/; s/^XPASS/PASS/' < "$1" | awk '/^[ ]*=== [^ ]* tests ===$/ {tool = $2} /^Running target / {target = $3} { if (tool != "") { sub(/:[ ]/, "&"tool": " ); }; if (target != "unix") { sub(/:[ ]/, "&"target": " ); }; print $0; }' | cut -c1-2000 >$tmp1
|
||||
sed 's/^XFAIL/FAIL/; s/^ERROR/FAIL/; s/^XPASS/PASS/' < "$2" | awk '/^[ ]*=== [^ ]* tests ===$/ {tool = $2} /^Running target / {target = $3} { if (tool != "") { sub(/:[ ]/, "&"tool": " ); }; if (target != "unix") { sub(/:[ ]/, "&"target": " ); }; print $0; }' | cut -c1-2000 >$tmp2
|
||||
|
||||
before=$tmp1
|
||||
now=$tmp2
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ git config alias.gcc-backport '!f() { "`git rev-parse --show-toplevel`/contrib/g
|
|||
git config alias.gcc-fix-changelog '!f() { "`git rev-parse --show-toplevel`/contrib/git-fix-changelog.py" $@; } ; f'
|
||||
git config alias.gcc-mklog '!f() { "`git rev-parse --show-toplevel`/contrib/mklog.py" $@; } ; f'
|
||||
git config alias.gcc-commit-mklog '!f() { "`git rev-parse --show-toplevel`/contrib/git-commit-mklog.py" "$@"; }; f'
|
||||
git config alias.gcc-style '!f() {
|
||||
check=`git rev-parse --show-toplevel`/contrib/check_GNU_style.py;
|
||||
arg=; if [ $# -ge 1 ] && [ "$1" != "-f" ]; then arg="$1"; shift;
|
||||
elif [ $# -eq 3 ]; then arg="$3"; set -- "$1" "$2"; fi
|
||||
git show $arg | $check "$@" -; }; f'
|
||||
|
||||
# Make diff on MD files use "(define" as a function marker.
|
||||
# Use this in conjunction with a .gitattributes file containing
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2013-2023 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2013-2024 Free Software Foundation, Inc.
|
||||
#
|
||||
# This script is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -83,6 +83,7 @@ class GenericFilter:
|
|||
'gpl_v3.texi',
|
||||
'fdl-1.3.xml',
|
||||
'gpl-3.0.xml',
|
||||
'gpl_v3_without_node.texi',
|
||||
|
||||
# Skip auto- and libtool-related files
|
||||
'aclocal.m4',
|
||||
|
|
@ -556,6 +557,9 @@ class GCCFilter (GenericFilter):
|
|||
self.skip_files |= set ([
|
||||
# Not part of GCC
|
||||
'math-68881.h',
|
||||
|
||||
# Weird ways to compose copyright year
|
||||
'GmcOptions.cc',
|
||||
])
|
||||
|
||||
self.skip_dirs |= set ([
|
||||
|
|
|
|||
53039
gcc/ChangeLog
53039
gcc/ChangeLog
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1 +1 @@
|
|||
20231214
|
||||
20240103
|
||||
|
|
|
|||
|
|
@ -4304,6 +4304,7 @@ $(lang_checks_parallel): site.exp
|
|||
vardots=`echo "$$variant" | sed 's,/,.,g'`; \
|
||||
$(MAKE) TESTSUITEDIR="testsuite.$$vardots" \
|
||||
RUNTESTFLAGS="--target_board=$$variant $(RUNTESTFLAGS)" \
|
||||
EXPECT=$(EXPECT) \
|
||||
"$$target"
|
||||
|
||||
TESTSUITEDIR = testsuite
|
||||
|
|
@ -4369,6 +4370,7 @@ $(lang_checks_parallelized): check-% : site.exp
|
|||
GCC_RUNTEST_PARALLELIZE_DIR=`${PWD_COMMAND}`/$(TESTSUITEDIR)/$(check_p_tool)-parallel ; \
|
||||
export GCC_RUNTEST_PARALLELIZE_DIR ; \
|
||||
$(MAKE) TESTSUITEDIR="$(TESTSUITEDIR)" RUNTESTFLAGS="$(RUNTESTFLAGS)" \
|
||||
EXPECT=$(EXPECT) \
|
||||
check-parallel-$* \
|
||||
$(patsubst %,check-parallel-$*_%, $(check_p_subdirs)); \
|
||||
sums= ; logs= ; \
|
||||
|
|
@ -4387,6 +4389,7 @@ $(lang_checks_parallelized): check-% : site.exp
|
|||
rm -rf $(TESTSUITEDIR)/$*-parallel || true; \
|
||||
else \
|
||||
$(MAKE) TESTSUITEDIR="$(TESTSUITEDIR)" RUNTESTFLAGS="$(RUNTESTFLAGS)" \
|
||||
EXPECT=$(EXPECT) \
|
||||
check_$*_parallelize= check-parallel-$*; \
|
||||
fi
|
||||
|
||||
|
|
|
|||
6742
gcc/ada/ChangeLog
6742
gcc/ada/ChangeLog
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -51,7 +51,9 @@
|
|||
#include "system.h"
|
||||
#endif
|
||||
|
||||
#ifndef LIGHT_RUNTIME
|
||||
#include "adaint.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,15 @@ package body Bindgen is
|
|||
-- Number of default-sized primary stacks the binder needs to allocate for
|
||||
-- task objects declared in the program.
|
||||
|
||||
Command_Line_Used : Boolean := False;
|
||||
-- Flag indicating whether the unit Ada.Command_Line is in the closure of
|
||||
-- the partition. This is set by Resolve_Binder_Options, and is used to
|
||||
-- determine whether or not to import and use symbols defined in
|
||||
-- Ada.Command_Line's support packages (gnat_argc, gnat_argv, gnat_envp
|
||||
-- and gnat_exit_status). Conservatively, it is always set to True for
|
||||
-- non-configurable run-times as parts of the compiler and run-time assume
|
||||
-- these symbols are available and can be imported directly.
|
||||
|
||||
System_Restrictions_Used : Boolean := False;
|
||||
-- Flag indicating whether the unit System.Restrictions is in the closure
|
||||
-- of the partition. This is set by Resolve_Binder_Options, and is used
|
||||
|
|
@ -2092,13 +2101,13 @@ package body Bindgen is
|
|||
|
||||
WBI (" begin");
|
||||
|
||||
-- Acquire command-line arguments if present on target
|
||||
-- Acquire command-line arguments if supported on the target and used
|
||||
-- by the program.
|
||||
|
||||
if CodePeer_Mode then
|
||||
null;
|
||||
|
||||
elsif Command_Line_Args_On_Target then
|
||||
|
||||
elsif Command_Line_Args_On_Target and then Command_Line_Used then
|
||||
-- Initialize gnat_argc/gnat_argv only if not already initialized,
|
||||
-- to avoid losing the result of any command-line processing done by
|
||||
-- earlier GNAT run-time initialization.
|
||||
|
|
@ -2109,20 +2118,6 @@ package body Bindgen is
|
|||
WBI (" end if;");
|
||||
WBI (" gnat_envp := envp;");
|
||||
WBI ("");
|
||||
|
||||
-- If configurable run-time and no command-line args, then nothing needs
|
||||
-- to be done since the gnat_argc/argv/envp variables are suppressed in
|
||||
-- this case.
|
||||
|
||||
elsif Configurable_Run_Time_On_Target then
|
||||
null;
|
||||
|
||||
-- Otherwise set dummy values (to be filled in by some other unit?)
|
||||
|
||||
else
|
||||
WBI (" gnat_argc := 0;");
|
||||
WBI (" gnat_argv := System.Null_Address;");
|
||||
WBI (" gnat_envp := System.Null_Address;");
|
||||
end if;
|
||||
|
||||
if Opt.Default_Exit_Status /= 0
|
||||
|
|
@ -2199,7 +2194,14 @@ package body Bindgen is
|
|||
if No_Main_Subprogram
|
||||
or else ALIs.Table (ALIs.First).Main_Program = Proc
|
||||
then
|
||||
WBI (" return (gnat_exit_status);");
|
||||
-- Return gnat_exit_status if Ada.Command_Line is used otherwise
|
||||
-- return 0.
|
||||
|
||||
if Command_Line_Used then
|
||||
WBI (" return (gnat_exit_status);");
|
||||
else
|
||||
WBI (" return (0);");
|
||||
end if;
|
||||
else
|
||||
WBI (" return (Result);");
|
||||
end if;
|
||||
|
|
@ -2595,38 +2597,35 @@ package body Bindgen is
|
|||
if Bind_Main_Program then
|
||||
-- Generate argc/argv stuff unless suppressed
|
||||
|
||||
if Command_Line_Args_On_Target
|
||||
or not Configurable_Run_Time_On_Target
|
||||
then
|
||||
-- A run-time configured to support command line arguments defines
|
||||
-- a number of internal symbols that need to be set by the binder.
|
||||
-- We do not do this in cases where the program does not use
|
||||
-- Ada.Command_Line, as the package and it's support files may not be
|
||||
-- present.
|
||||
|
||||
if Command_Line_Args_On_Target and then Command_Line_Used then
|
||||
WBI ("");
|
||||
WBI (" gnat_argc : Integer;");
|
||||
WBI (" gnat_argv : System.Address;");
|
||||
WBI (" gnat_envp : System.Address;");
|
||||
|
||||
-- If the standard library is not suppressed, these variables
|
||||
-- are in the run-time data area for easy run time access.
|
||||
|
||||
if not Suppress_Standard_Library_On_Target then
|
||||
WBI ("");
|
||||
WBI (" pragma Import (C, gnat_argc);");
|
||||
WBI (" pragma Import (C, gnat_argv);");
|
||||
WBI (" pragma Import (C, gnat_envp);");
|
||||
end if;
|
||||
WBI ("");
|
||||
WBI (" pragma Import (C, gnat_argc);");
|
||||
WBI (" pragma Import (C, gnat_argv);");
|
||||
WBI (" pragma Import (C, gnat_envp);");
|
||||
end if;
|
||||
|
||||
-- Define exit status. Again in normal mode, this is in the run-time
|
||||
-- library, and is initialized there, but in the configurable
|
||||
-- run-time case, the variable is declared and initialized in this
|
||||
-- file.
|
||||
-- Define exit status if supported by the target. The exit status is
|
||||
-- stored in the run-time library to allow applications set the state
|
||||
-- through Ada.Command_Line and is initialized in the run-time. Like
|
||||
-- command line arguments, skip if Ada.Command_Line is not used in
|
||||
-- the enclosure of the partition because this package may not be
|
||||
-- available in the runtime.
|
||||
|
||||
WBI ("");
|
||||
|
||||
if Configurable_Run_Time_Mode then
|
||||
if Exit_Status_Supported_On_Target then
|
||||
WBI (" gnat_exit_status : Integer := 0;");
|
||||
end if;
|
||||
|
||||
else
|
||||
if Exit_Status_Supported_On_Target and then Command_Line_Used
|
||||
then
|
||||
WBI (" gnat_exit_status : Integer;");
|
||||
WBI (" pragma Import (C, gnat_exit_status);");
|
||||
end if;
|
||||
|
|
@ -3389,6 +3388,18 @@ package body Bindgen is
|
|||
|
||||
Check_Package (System_Version_Control_Used,
|
||||
"system.version_control%s");
|
||||
|
||||
-- Ditto for the use of Ada.Command_Line, except we always set
|
||||
-- Command_Line_Used to True if on a non-configurable run-time
|
||||
-- as parts of the compiler and run-time assume the GNAT command
|
||||
-- line symbols are available and can be imported directly (as
|
||||
-- long as No_Run_Time mode is not set).
|
||||
|
||||
if Configurable_Run_Time_On_Target then
|
||||
Check_Package (Command_Line_Used, "ada.command_line%s");
|
||||
elsif not No_Run_Time_Mode then
|
||||
Command_Line_Used := True;
|
||||
end if;
|
||||
end loop;
|
||||
end Resolve_Binder_Options;
|
||||
|
||||
|
|
|
|||
|
|
@ -2472,7 +2472,9 @@ Syntax:
|
|||
This is a configuration pragma
|
||||
that takes a single argument that is a simple identifier. Any subsequent
|
||||
use of a pragma whose pragma identifier matches this argument will be
|
||||
silently ignored. This may be useful when legacy code or code intended
|
||||
silently ignored. Any preceding use of a pragma whose pragma identifier
|
||||
matches this argument will be parsed and then ignored.
|
||||
This may be useful when legacy code or code intended
|
||||
for compilation with some other compiler contains pragmas that match the
|
||||
name, but not the exact implementation, of a GNAT pragma. The use of this
|
||||
pragma allows such pragmas to be ignored, which may be useful in CodePeer
|
||||
|
|
|
|||
|
|
@ -2474,17 +2474,17 @@ package Einfo is
|
|||
-- and subtypes, string types and subtypes, and all numeric types).
|
||||
-- Set if the type or subtype is constrained.
|
||||
|
||||
-- Is_Constr_Array_Subt_With_Bounds
|
||||
-- Defined in all types and subtypes. Set only for an array subtype
|
||||
-- which is constrained but nevertheless requires objects of this
|
||||
-- subtype to be allocated with their bounds. This flag is used by
|
||||
-- the back end to determine whether the bounds must be constructed.
|
||||
|
||||
-- Is_Constr_Subt_For_U_Nominal
|
||||
-- Defined in all types and subtypes. Set only for the constructed
|
||||
-- subtype of an object whose nominal subtype is unconstrained. Note
|
||||
-- that the constructed subtype itself will be constrained.
|
||||
|
||||
-- Is_Constr_Subt_For_UN_Aliased
|
||||
-- Defined in all types and subtypes. This flag can be set only if
|
||||
-- Is_Constr_Subt_For_U_Nominal is also set. It indicates that in
|
||||
-- addition the object concerned is aliased. This flag is used by
|
||||
-- the backend to determine whether a template must be constructed.
|
||||
|
||||
-- Is_Constructor
|
||||
-- Defined in function and procedure entities. Set if a pragma
|
||||
-- CPP_Constructor applies to the subprogram.
|
||||
|
|
@ -2727,6 +2727,11 @@ package Einfo is
|
|||
-- instantiation of a child unit, and whose entities are not visible
|
||||
-- during analysis of the instance.
|
||||
|
||||
-- Is_Ignored_For_Finalization
|
||||
-- Defined in constants and variables. Set when an object must be ignored
|
||||
-- by the general finalization mechanism because its cleanup actions are
|
||||
-- already accounted for.
|
||||
|
||||
-- Is_Ignored_Ghost_Entity
|
||||
-- Applies to all entities. Set for abstract states, [generic] packages,
|
||||
-- [generic] subprograms, components, discriminants, formal parameters,
|
||||
|
|
@ -2734,13 +2739,6 @@ package Einfo is
|
|||
-- pragma Ghost or inherit "ghostness" from an enclosing construct, and
|
||||
-- subject to Assertion_Policy Ghost => Ignore.
|
||||
|
||||
-- Is_Ignored_Transient
|
||||
-- Defined in constants, loop parameters of generalized iterators, and
|
||||
-- variables. Set when a transient object must be processed by one of
|
||||
-- the transient finalization mechanisms. Once marked, a transient is
|
||||
-- intentionally ignored by the general finalization mechanism because
|
||||
-- its clean up actions are context specific.
|
||||
|
||||
-- Is_Immediately_Visible
|
||||
-- Defined in all entities. Set if entity is immediately visible, i.e.
|
||||
-- is defined in some currently open scope (RM 8.3(4)).
|
||||
|
|
@ -5060,8 +5058,8 @@ package Einfo is
|
|||
-- Is_Abstract_Type
|
||||
-- Is_Asynchronous
|
||||
-- Is_Atomic
|
||||
-- Is_Constr_Array_Subt_With_Bounds
|
||||
-- Is_Constr_Subt_For_U_Nominal
|
||||
-- Is_Constr_Subt_For_UN_Aliased
|
||||
-- Is_Controlled_Active (base type only)
|
||||
-- Is_Eliminated
|
||||
-- Is_Frozen
|
||||
|
|
@ -5325,7 +5323,7 @@ package Einfo is
|
|||
-- Is_Elaboration_Warnings_OK_Id (constants only)
|
||||
-- Is_Eliminated
|
||||
-- Is_Finalized_Transient
|
||||
-- Is_Ignored_Transient
|
||||
-- Is_Ignored_For_Finalization
|
||||
-- Is_Independent
|
||||
-- Is_Return_Object
|
||||
-- Is_True_Constant
|
||||
|
|
@ -6213,7 +6211,7 @@ package Einfo is
|
|||
-- Is_Elaboration_Warnings_OK_Id
|
||||
-- Is_Eliminated
|
||||
-- Is_Finalized_Transient
|
||||
-- Is_Ignored_Transient
|
||||
-- Is_Ignored_For_Finalization
|
||||
-- Is_Independent
|
||||
-- Is_Return_Object
|
||||
-- Is_Safe_To_Reevaluate
|
||||
|
|
|
|||
|
|
@ -185,6 +185,11 @@ package body Errout is
|
|||
-- Outputs up to N levels of qualification for the given entity. For
|
||||
-- example, the entity A.B.C.D will output B.C. if N = 2.
|
||||
|
||||
function Should_Ignore_Pragma_SPARK_Mode return Boolean;
|
||||
-- Return whether pragma Ignore_Pragma (SPARK_Mode) was specified. This is
|
||||
-- similar to Sem_Util.Should_Ignore_Pragma_Par but located here to avoid
|
||||
-- problematic dependency on Sem_Util.
|
||||
|
||||
function Special_Msg_Delete
|
||||
(Msg : String;
|
||||
N : Node_Or_Entity_Id;
|
||||
|
|
@ -4459,6 +4464,15 @@ package body Errout is
|
|||
end if;
|
||||
end Set_Qualification;
|
||||
|
||||
-------------------------------------
|
||||
-- Should_Ignore_Pragma_SPARK_Mode --
|
||||
-------------------------------------
|
||||
|
||||
function Should_Ignore_Pragma_SPARK_Mode return Boolean is
|
||||
begin
|
||||
return Get_Name_Table_Boolean3 (Name_SPARK_Mode);
|
||||
end Should_Ignore_Pragma_SPARK_Mode;
|
||||
|
||||
------------------------
|
||||
-- Special_Msg_Delete --
|
||||
------------------------
|
||||
|
|
@ -4522,7 +4536,14 @@ package body Errout is
|
|||
|
||||
procedure SPARK_Msg_N (Msg : String; N : Node_Or_Entity_Id) is
|
||||
begin
|
||||
if SPARK_Mode /= Off then
|
||||
-- If SPARK_Mode is Off, we do not report SPARK legality errors to give
|
||||
-- the flexibility to opt out of SPARK checking completely. We do the
|
||||
-- same if pragma Ignore_Pragma (SPARK_Mode) was specified, as a way
|
||||
-- for tools to ignore SPARK checking even on SPARK code.
|
||||
|
||||
if SPARK_Mode /= Off
|
||||
and then not Should_Ignore_Pragma_SPARK_Mode
|
||||
then
|
||||
Error_Msg_N (Msg, N);
|
||||
end if;
|
||||
end SPARK_Msg_N;
|
||||
|
|
@ -4537,7 +4558,9 @@ package body Errout is
|
|||
E : Node_Or_Entity_Id)
|
||||
is
|
||||
begin
|
||||
if SPARK_Mode /= Off then
|
||||
if SPARK_Mode /= Off
|
||||
and then not Should_Ignore_Pragma_SPARK_Mode
|
||||
then
|
||||
Error_Msg_NE (Msg, N, E);
|
||||
end if;
|
||||
end SPARK_Msg_NE;
|
||||
|
|
|
|||
|
|
@ -6317,7 +6317,7 @@ package body Exp_Aggr is
|
|||
and then No_Ctrl_Actions (Parent_Node)
|
||||
then
|
||||
Mutate_Ekind (Tmp, E_Variable);
|
||||
Set_Is_Ignored_Transient (Tmp);
|
||||
Set_Is_Ignored_For_Finalization (Tmp);
|
||||
end if;
|
||||
|
||||
Insert_Action (N, Tmp_Decl);
|
||||
|
|
@ -8509,9 +8509,18 @@ package body Exp_Aggr is
|
|||
Set_No_Ctrl_Actions (Init_Stmt);
|
||||
|
||||
if Tagged_Type_Expansion and then Is_Tagged_Type (Comp_Typ) then
|
||||
Append_To (Blk_Stmts,
|
||||
Make_Tag_Assignment_From_Type
|
||||
(Loc, New_Copy_Tree (Comp), Underlying_Type (Comp_Typ)));
|
||||
declare
|
||||
Typ : Entity_Id := Underlying_Type (Comp_Typ);
|
||||
|
||||
begin
|
||||
if Is_Concurrent_Type (Typ) then
|
||||
Typ := Corresponding_Record_Type (Typ);
|
||||
end if;
|
||||
|
||||
Append_To (Blk_Stmts,
|
||||
Make_Tag_Assignment_From_Type
|
||||
(Loc, New_Copy_Tree (Comp), Typ));
|
||||
end;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
|
|
|
|||
|
|
@ -8107,8 +8107,7 @@ package body Exp_Ch3 is
|
|||
-- initialization expression has an unconstrained subtype too,
|
||||
-- because the bounds must be present within X.
|
||||
|
||||
and then not (Is_Array_Type (Typ)
|
||||
and then Is_Constr_Subt_For_UN_Aliased (Typ)
|
||||
and then not (Is_Constr_Array_Subt_With_Bounds (Typ)
|
||||
and then Is_Constrained (Etype (Expr_Q)))
|
||||
|
||||
-- We may use a renaming if the initialization expression is a
|
||||
|
|
|
|||
|
|
@ -241,23 +241,22 @@ package body Exp_Ch4 is
|
|||
-- and X is a simple entity, and op is a comparison operator, optimizes it
|
||||
-- into a comparison of X'First and X'Last.
|
||||
|
||||
procedure Process_If_Case_Statements (N : Node_Id; Stmts : List_Id);
|
||||
-- Inspect and process statement list Stmt of if or case expression N for
|
||||
-- transient objects. If such objects are found, the routine generates code
|
||||
-- to clean them up when the context of the expression is evaluated.
|
||||
|
||||
procedure Process_Transient_In_Expression
|
||||
(Obj_Decl : Node_Id;
|
||||
Expr : Node_Id;
|
||||
Stmts : List_Id);
|
||||
procedure Process_Transients_In_Expression
|
||||
(Expr : Node_Id;
|
||||
Stmts : List_Id);
|
||||
-- Subsidiary routine to the expansion of expression_with_actions, if and
|
||||
-- case expressions. Generate all necessary code to finalize a transient
|
||||
-- object when the enclosing context is elaborated or evaluated. Obj_Decl
|
||||
-- denotes the declaration of the transient object, which is usually the
|
||||
-- result of a controlled function call. Expr denotes the expression with
|
||||
-- actions, if expression, or case expression node. Stmts denotes the
|
||||
-- statement list which contains Decl, either at the top level or within a
|
||||
-- nested construct.
|
||||
-- case expressions. Inspect and process actions list Stmts of expression
|
||||
-- Expr for transient objects. If such objects are found, the routine will
|
||||
-- generate code to finalize them when the enclosing context is elaborated
|
||||
-- or evaluated.
|
||||
|
||||
-- This specific processing is required for these expressions because the
|
||||
-- management of transient objects for expressions implemented in Exp_Ch7
|
||||
-- cannot deal with nested lists of actions whose effects may outlive the
|
||||
-- lists and affect the result of the parent expressions. In these cases,
|
||||
-- the lifetime of temporaries created in these lists must be extended to
|
||||
-- match that of the enclosing context of the parent expressions and, in
|
||||
-- particular, their finalization must be deferred to this context.
|
||||
|
||||
procedure Rewrite_Comparison (N : Node_Id);
|
||||
-- If N is the node for a comparison whose outcome can be determined at
|
||||
|
|
@ -5411,14 +5410,10 @@ package body Exp_Ch4 is
|
|||
Statements => Stmts));
|
||||
|
||||
-- Finalize any transient objects on exit from the alternative.
|
||||
-- This needs to be done only when the case expression is _not_
|
||||
-- later converted into an expression with actions, which already
|
||||
-- contains this form of processing, and after Stmts is attached
|
||||
-- Note that this needs to be done only after Stmts is attached
|
||||
-- to the Alternatives list above (for Safe_To_Capture_Value).
|
||||
|
||||
if Optimize_Return_Stmt or else not Is_Copy_Type (Typ) then
|
||||
Process_If_Case_Statements (N, Stmts);
|
||||
end if;
|
||||
Process_Transients_In_Expression (N, Stmts);
|
||||
end;
|
||||
|
||||
Next (Alt);
|
||||
|
|
@ -5482,12 +5477,6 @@ package body Exp_Ch4 is
|
|||
procedure Force_Boolean_Evaluation (Expr : Node_Id);
|
||||
-- Force the evaluation of Boolean expression Expr
|
||||
|
||||
function Process_Action (Act : Node_Id) return Traverse_Result;
|
||||
-- Inspect and process a single action of an expression_with_actions for
|
||||
-- transient objects. If such objects are found, the routine generates
|
||||
-- code to clean them up when the context of the expression is evaluated
|
||||
-- or elaborated.
|
||||
|
||||
------------------------------
|
||||
-- Force_Boolean_Evaluation --
|
||||
------------------------------
|
||||
|
|
@ -5520,42 +5509,6 @@ package body Exp_Ch4 is
|
|||
Analyze (Expression (N));
|
||||
end Force_Boolean_Evaluation;
|
||||
|
||||
--------------------
|
||||
-- Process_Action --
|
||||
--------------------
|
||||
|
||||
function Process_Action (Act : Node_Id) return Traverse_Result is
|
||||
begin
|
||||
if Nkind (Act) = N_Object_Declaration
|
||||
and then Is_Finalizable_Transient (Act, N)
|
||||
then
|
||||
Process_Transient_In_Expression (Act, N, Acts);
|
||||
return Skip;
|
||||
|
||||
-- Avoid processing temporary function results multiple times when
|
||||
-- dealing with nested expression_with_actions or nested blocks.
|
||||
-- Similarly, do not process temporary function results in loops.
|
||||
-- This is done by Expand_N_Loop_Statement and Build_Finalizer.
|
||||
-- Note that we used to wrongly return Abandon instead of Skip here:
|
||||
-- this is wrong since it means that we were ignoring lots of
|
||||
-- relevant subsequent statements.
|
||||
|
||||
elsif Nkind (Act) in N_Expression_With_Actions
|
||||
| N_Block_Statement
|
||||
| N_Loop_Statement
|
||||
then
|
||||
return Skip;
|
||||
end if;
|
||||
|
||||
return OK;
|
||||
end Process_Action;
|
||||
|
||||
procedure Process_Single_Action is new Traverse_Proc (Process_Action);
|
||||
|
||||
-- Local variables
|
||||
|
||||
Act : Node_Id;
|
||||
|
||||
-- Start of processing for Expand_N_Expression_With_Actions
|
||||
|
||||
begin
|
||||
|
|
@ -5616,14 +5569,9 @@ package body Exp_Ch4 is
|
|||
Force_Evaluation (Expression (N));
|
||||
end if;
|
||||
|
||||
-- Process all transient objects found within the actions of the EWA
|
||||
-- node.
|
||||
-- Process transient objects found within the actions of the EWA node
|
||||
|
||||
Act := First (Acts);
|
||||
while Present (Act) loop
|
||||
Process_Single_Action (Act);
|
||||
Next (Act);
|
||||
end loop;
|
||||
Process_Transients_In_Expression (N, Acts);
|
||||
|
||||
-- Deal with case where there are no actions. In this case we simply
|
||||
-- rewrite the node with its expression since we don't need the actions
|
||||
|
|
@ -5683,10 +5631,6 @@ package body Exp_Ch4 is
|
|||
UI_Max (Hi1, Hi2) - UI_Min (Lo1, Lo2) < Too_Large_Length_For_Array;
|
||||
end OK_For_Single_Subtype;
|
||||
|
||||
Optimize_Return_Stmt : Boolean := False;
|
||||
-- Flag set when the if expression can be optimized in the context of
|
||||
-- a simple return statement.
|
||||
|
||||
-- Local variables
|
||||
|
||||
Actions : List_Id;
|
||||
|
|
@ -5695,6 +5639,10 @@ package body Exp_Ch4 is
|
|||
New_If : Node_Id;
|
||||
New_N : Node_Id;
|
||||
|
||||
Optimize_Return_Stmt : Boolean := False;
|
||||
-- Flag set when the if expression can be optimized in the context of
|
||||
-- a simple return statement.
|
||||
|
||||
-- Start of processing for Expand_N_If_Expression
|
||||
|
||||
begin
|
||||
|
|
@ -5802,8 +5750,8 @@ package body Exp_Ch4 is
|
|||
-- of actions. These temporaries need to be finalized after the if
|
||||
-- expression is evaluated.
|
||||
|
||||
Process_If_Case_Statements (N, Then_Actions (N));
|
||||
Process_If_Case_Statements (N, Else_Actions (N));
|
||||
Process_Transients_In_Expression (N, Then_Actions (N));
|
||||
Process_Transients_In_Expression (N, Else_Actions (N));
|
||||
|
||||
New_If :=
|
||||
Make_Implicit_If_Statement (N,
|
||||
|
|
@ -5843,8 +5791,8 @@ package body Exp_Ch4 is
|
|||
-- of actions. These temporaries need to be finalized after the if
|
||||
-- expression is evaluated.
|
||||
|
||||
Process_If_Case_Statements (N, Then_Actions (N));
|
||||
Process_If_Case_Statements (N, Else_Actions (N));
|
||||
Process_Transients_In_Expression (N, Then_Actions (N));
|
||||
Process_Transients_In_Expression (N, Else_Actions (N));
|
||||
|
||||
declare
|
||||
Cnn : constant Entity_Id := Make_Temporary (Loc, 'C', N);
|
||||
|
|
@ -5952,6 +5900,14 @@ package body Exp_Ch4 is
|
|||
and then not Generate_C_Code
|
||||
and then not Unnest_Subprogram_Mode
|
||||
then
|
||||
-- When the "then" or "else" expressions involve controlled function
|
||||
-- calls, generated temporaries are chained on the corresponding list
|
||||
-- of actions. These temporaries need to be finalized after the if
|
||||
-- expression is evaluated.
|
||||
|
||||
Process_Transients_In_Expression (N, Then_Actions (N));
|
||||
Process_Transients_In_Expression (N, Else_Actions (N));
|
||||
|
||||
declare
|
||||
Ityp : constant Entity_Id := Base_Type (Etype (First_Index (Typ)));
|
||||
|
||||
|
|
@ -6186,13 +6142,20 @@ package body Exp_Ch4 is
|
|||
or else Present (Else_Actions (N))
|
||||
or else Force_Expand
|
||||
then
|
||||
|
||||
-- We now wrap the actions into the appropriate expression
|
||||
|
||||
if Minimize_Expression_With_Actions
|
||||
and then (Is_Elementary_Type (Underlying_Type (Typ))
|
||||
or else Is_Constrained (Underlying_Type (Typ)))
|
||||
then
|
||||
-- When the "then" or "else" expressions involve controlled
|
||||
-- function calls, generated temporaries are chained on the
|
||||
-- corresponding list of actions. These temporaries need to
|
||||
-- be finalized after the if expression is evaluated.
|
||||
|
||||
Process_Transients_In_Expression (N, Then_Actions (N));
|
||||
Process_Transients_In_Expression (N, Else_Actions (N));
|
||||
|
||||
-- If we can't use N_Expression_With_Actions nodes, then we insert
|
||||
-- the following sequence of actions (using Insert_Actions):
|
||||
|
||||
|
|
@ -6239,6 +6202,10 @@ package body Exp_Ch4 is
|
|||
-- Regular path using Expression_With_Actions
|
||||
|
||||
else
|
||||
-- We do not need to call Process_Transients_In_Expression on
|
||||
-- the list of actions in this case, because the expansion of
|
||||
-- Expression_With_Actions will do it.
|
||||
|
||||
if Present (Then_Actions (N)) then
|
||||
Rewrite (Thenx,
|
||||
Make_Expression_With_Actions (Sloc (Thenx),
|
||||
|
|
@ -14938,183 +14905,194 @@ package body Exp_Ch4 is
|
|||
Analyze_And_Resolve (N, Typ, Suppress => Overflow_Check);
|
||||
end Optimize_Length_Comparison;
|
||||
|
||||
--------------------------------
|
||||
-- Process_If_Case_Statements --
|
||||
--------------------------------
|
||||
--------------------------------------
|
||||
-- Process_Transients_In_Expression --
|
||||
--------------------------------------
|
||||
|
||||
procedure Process_If_Case_Statements (N : Node_Id; Stmts : List_Id) is
|
||||
Decl : Node_Id;
|
||||
procedure Process_Transients_In_Expression
|
||||
(Expr : Node_Id;
|
||||
Stmts : List_Id)
|
||||
is
|
||||
procedure Process_Transient_In_Expression (Obj_Decl : Node_Id);
|
||||
-- Process the object whose declaration Obj_Decl is present in Stmts
|
||||
|
||||
begin
|
||||
Decl := First (Stmts);
|
||||
while Present (Decl) loop
|
||||
if Nkind (Decl) = N_Object_Declaration
|
||||
and then Is_Finalizable_Transient (Decl, N)
|
||||
-------------------------------------
|
||||
-- Process_Transient_In_Expression --
|
||||
-------------------------------------
|
||||
|
||||
procedure Process_Transient_In_Expression (Obj_Decl : Node_Id) is
|
||||
Loc : constant Source_Ptr := Sloc (Obj_Decl);
|
||||
Obj_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
|
||||
|
||||
Hook_Context : constant Node_Id := Find_Hook_Context (Expr);
|
||||
-- The node on which to insert the hook as an action. This is usually
|
||||
-- the innermost enclosing non-transient construct.
|
||||
|
||||
Fin_Call : Node_Id;
|
||||
Hook_Assign : Node_Id;
|
||||
Hook_Clear : Node_Id;
|
||||
Hook_Decl : Node_Id;
|
||||
Hook_Insert : Node_Id;
|
||||
Ptr_Decl : Node_Id;
|
||||
|
||||
Fin_Context : Node_Id;
|
||||
-- The node after which to insert the finalization actions of the
|
||||
-- transient object.
|
||||
|
||||
begin
|
||||
pragma Assert (Nkind (Expr) in N_Case_Expression
|
||||
| N_Expression_With_Actions
|
||||
| N_If_Expression);
|
||||
|
||||
-- When the context is a Boolean evaluation, all three nodes capture
|
||||
-- the result of their computation in a local temporary:
|
||||
|
||||
-- do
|
||||
-- Trans_Id : Ctrl_Typ := ...;
|
||||
-- Result : constant Boolean := ... Trans_Id ...;
|
||||
-- <finalize Trans_Id>
|
||||
-- in Result end;
|
||||
|
||||
-- As a result, the finalization of any transient objects can take
|
||||
-- place just after the result is captured, except for the case of
|
||||
-- conditional expressions in a simple return statement because the
|
||||
-- return statement will be distributed into dependent expressions
|
||||
-- (see the special handling of simple return statements below).
|
||||
|
||||
-- ??? could this be extended to elementary types?
|
||||
|
||||
if Is_Boolean_Type (Etype (Expr))
|
||||
and then
|
||||
(Nkind (Expr) = N_Expression_With_Actions
|
||||
or else Nkind (Parent (Expr)) /= N_Simple_Return_Statement)
|
||||
then
|
||||
Process_Transient_In_Expression (Decl, N, Stmts);
|
||||
Fin_Context := Last (Stmts);
|
||||
|
||||
-- Otherwise the immediate context may not be safe enough to carry
|
||||
-- out transient object finalization due to aliasing and nesting of
|
||||
-- constructs. Insert calls to [Deep_]Finalize after the innermost
|
||||
-- enclosing non-transient construct.
|
||||
|
||||
else
|
||||
Fin_Context := Hook_Context;
|
||||
end if;
|
||||
|
||||
Next (Decl);
|
||||
end loop;
|
||||
end Process_If_Case_Statements;
|
||||
-- Mark the transient object as successfully processed to avoid
|
||||
-- double finalization.
|
||||
|
||||
-------------------------------------
|
||||
-- Process_Transient_In_Expression --
|
||||
-------------------------------------
|
||||
Set_Is_Finalized_Transient (Obj_Id);
|
||||
|
||||
procedure Process_Transient_In_Expression
|
||||
(Obj_Decl : Node_Id;
|
||||
Expr : Node_Id;
|
||||
Stmts : List_Id)
|
||||
is
|
||||
Loc : constant Source_Ptr := Sloc (Obj_Decl);
|
||||
Obj_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
|
||||
-- Construct all the pieces necessary to hook and finalize a
|
||||
-- transient object.
|
||||
|
||||
Hook_Context : constant Node_Id := Find_Hook_Context (Expr);
|
||||
-- The node on which to insert the hook as an action. This is usually
|
||||
-- the innermost enclosing non-transient construct.
|
||||
Build_Transient_Object_Statements
|
||||
(Obj_Decl => Obj_Decl,
|
||||
Fin_Call => Fin_Call,
|
||||
Hook_Assign => Hook_Assign,
|
||||
Hook_Clear => Hook_Clear,
|
||||
Hook_Decl => Hook_Decl,
|
||||
Ptr_Decl => Ptr_Decl,
|
||||
Finalize_Obj => False);
|
||||
|
||||
Fin_Call : Node_Id;
|
||||
Hook_Assign : Node_Id;
|
||||
Hook_Clear : Node_Id;
|
||||
Hook_Decl : Node_Id;
|
||||
Hook_Insert : Node_Id;
|
||||
Ptr_Decl : Node_Id;
|
||||
-- Add the access type which provides a reference to the transient
|
||||
-- object. Generate:
|
||||
|
||||
Fin_Context : Node_Id;
|
||||
-- The node after which to insert the finalization actions of the
|
||||
-- transient object.
|
||||
-- type Ptr_Typ is access all Desig_Typ;
|
||||
|
||||
Insert_Action (Hook_Context, Ptr_Decl);
|
||||
|
||||
-- Add the temporary which acts as a hook to the transient object.
|
||||
-- Generate:
|
||||
|
||||
-- Hook : Ptr_Id := null;
|
||||
|
||||
Insert_Action (Hook_Context, Hook_Decl);
|
||||
|
||||
-- When the transient object is initialized by an aggregate, the hook
|
||||
-- must capture the object after the last aggregate assignment takes
|
||||
-- place. Only then is the object considered initialized. Generate:
|
||||
|
||||
-- Hook := Ptr_Typ (Obj_Id);
|
||||
-- <or>
|
||||
-- Hook := Obj_Id'Unrestricted_Access;
|
||||
|
||||
if Ekind (Obj_Id) in E_Constant | E_Variable
|
||||
and then Present (Last_Aggregate_Assignment (Obj_Id))
|
||||
then
|
||||
Hook_Insert := Last_Aggregate_Assignment (Obj_Id);
|
||||
|
||||
-- Otherwise the hook seizes the related object immediately
|
||||
|
||||
else
|
||||
Hook_Insert := Obj_Decl;
|
||||
end if;
|
||||
|
||||
Insert_After_And_Analyze (Hook_Insert, Hook_Assign);
|
||||
|
||||
-- When the node is part of a return statement, there is no need to
|
||||
-- insert a finalization call, as the general finalization mechanism
|
||||
-- (see Build_Finalizer) would take care of the transient object on
|
||||
-- subprogram exit. Note that it would also be impossible to insert
|
||||
-- the finalization code after the return statement as this will
|
||||
-- render it unreachable.
|
||||
|
||||
if Nkind (Fin_Context) = N_Simple_Return_Statement then
|
||||
null;
|
||||
|
||||
-- Finalize the hook after the context has been evaluated. Generate:
|
||||
|
||||
-- if Hook /= null then
|
||||
-- [Deep_]Finalize (Hook.all);
|
||||
-- Hook := null;
|
||||
-- end if;
|
||||
|
||||
-- But the node returned by Find_Hook_Context may be an operator,
|
||||
-- which is not a list member. We must locate the proper node
|
||||
-- in the tree after which to insert the finalization code.
|
||||
|
||||
else
|
||||
while not Is_List_Member (Fin_Context) loop
|
||||
Fin_Context := Parent (Fin_Context);
|
||||
end loop;
|
||||
|
||||
pragma Assert (Present (Fin_Context));
|
||||
|
||||
Insert_Action_After (Fin_Context,
|
||||
Make_Implicit_If_Statement (Obj_Decl,
|
||||
Condition =>
|
||||
Make_Op_Ne (Loc,
|
||||
Left_Opnd =>
|
||||
New_Occurrence_Of (Defining_Entity (Hook_Decl), Loc),
|
||||
Right_Opnd => Make_Null (Loc)),
|
||||
|
||||
Then_Statements => New_List (
|
||||
Fin_Call,
|
||||
Hook_Clear)));
|
||||
end if;
|
||||
end Process_Transient_In_Expression;
|
||||
|
||||
-- Local variables
|
||||
|
||||
Decl : Node_Id;
|
||||
|
||||
-- Start of processing for Process_Transients_In_Expression
|
||||
|
||||
begin
|
||||
pragma Assert (Nkind (Expr) in N_Case_Expression
|
||||
| N_Expression_With_Actions
|
||||
| N_If_Expression);
|
||||
|
||||
-- When the context is a Boolean evaluation, all three nodes capture the
|
||||
-- result of their computation in a local temporary:
|
||||
Decl := First (Stmts);
|
||||
while Present (Decl) loop
|
||||
if Nkind (Decl) = N_Object_Declaration
|
||||
and then Is_Finalizable_Transient (Decl, Expr)
|
||||
then
|
||||
Process_Transient_In_Expression (Decl);
|
||||
end if;
|
||||
|
||||
-- do
|
||||
-- Trans_Id : Ctrl_Typ := ...;
|
||||
-- Result : constant Boolean := ... Trans_Id ...;
|
||||
-- <finalize Trans_Id>
|
||||
-- in Result end;
|
||||
|
||||
-- As a result, the finalization of any transient objects can take place
|
||||
-- just after the result is captured, except for the case of conditional
|
||||
-- expressions in a simple return statement because the return statement
|
||||
-- will be distributed into the conditional expressions (see the special
|
||||
-- handling of simple return statements a few lines below).
|
||||
|
||||
-- ??? could this be extended to elementary types?
|
||||
|
||||
if Is_Boolean_Type (Etype (Expr))
|
||||
and then (Nkind (Expr) = N_Expression_With_Actions
|
||||
or else Nkind (Parent (Expr)) /= N_Simple_Return_Statement)
|
||||
then
|
||||
Fin_Context := Last (Stmts);
|
||||
|
||||
-- Otherwise the immediate context may not be safe enough to carry
|
||||
-- out transient object finalization due to aliasing and nesting of
|
||||
-- constructs. Insert calls to [Deep_]Finalize after the innermost
|
||||
-- enclosing non-transient construct.
|
||||
|
||||
else
|
||||
Fin_Context := Hook_Context;
|
||||
end if;
|
||||
|
||||
-- Mark the transient object as successfully processed to avoid double
|
||||
-- finalization.
|
||||
|
||||
Set_Is_Finalized_Transient (Obj_Id);
|
||||
|
||||
-- Construct all the pieces necessary to hook and finalize a transient
|
||||
-- object.
|
||||
|
||||
Build_Transient_Object_Statements
|
||||
(Obj_Decl => Obj_Decl,
|
||||
Fin_Call => Fin_Call,
|
||||
Hook_Assign => Hook_Assign,
|
||||
Hook_Clear => Hook_Clear,
|
||||
Hook_Decl => Hook_Decl,
|
||||
Ptr_Decl => Ptr_Decl,
|
||||
Finalize_Obj => False);
|
||||
|
||||
-- Add the access type which provides a reference to the transient
|
||||
-- object. Generate:
|
||||
|
||||
-- type Ptr_Typ is access all Desig_Typ;
|
||||
|
||||
Insert_Action (Hook_Context, Ptr_Decl);
|
||||
|
||||
-- Add the temporary which acts as a hook to the transient object.
|
||||
-- Generate:
|
||||
|
||||
-- Hook : Ptr_Id := null;
|
||||
|
||||
Insert_Action (Hook_Context, Hook_Decl);
|
||||
|
||||
-- When the transient object is initialized by an aggregate, the hook
|
||||
-- must capture the object after the last aggregate assignment takes
|
||||
-- place. Only then is the object considered initialized. Generate:
|
||||
|
||||
-- Hook := Ptr_Typ (Obj_Id);
|
||||
-- <or>
|
||||
-- Hook := Obj_Id'Unrestricted_Access;
|
||||
|
||||
if Ekind (Obj_Id) in E_Constant | E_Variable
|
||||
and then Present (Last_Aggregate_Assignment (Obj_Id))
|
||||
then
|
||||
Hook_Insert := Last_Aggregate_Assignment (Obj_Id);
|
||||
|
||||
-- Otherwise the hook seizes the related object immediately
|
||||
|
||||
else
|
||||
Hook_Insert := Obj_Decl;
|
||||
end if;
|
||||
|
||||
Insert_After_And_Analyze (Hook_Insert, Hook_Assign);
|
||||
|
||||
-- When the node is part of a return statement, there is no need to
|
||||
-- insert a finalization call, as the general finalization mechanism
|
||||
-- (see Build_Finalizer) would take care of the transient object on
|
||||
-- subprogram exit. Note that it would also be impossible to insert the
|
||||
-- finalization code after the return statement as this will render it
|
||||
-- unreachable.
|
||||
|
||||
if Nkind (Fin_Context) = N_Simple_Return_Statement then
|
||||
null;
|
||||
|
||||
-- Finalize the hook after the context has been evaluated. Generate:
|
||||
|
||||
-- if Hook /= null then
|
||||
-- [Deep_]Finalize (Hook.all);
|
||||
-- Hook := null;
|
||||
-- end if;
|
||||
|
||||
-- Note that the value returned by Find_Hook_Context may be an operator
|
||||
-- node, which is not a list member. We must locate the proper node in
|
||||
-- in the tree after which to insert the finalization code.
|
||||
|
||||
else
|
||||
while not Is_List_Member (Fin_Context) loop
|
||||
Fin_Context := Parent (Fin_Context);
|
||||
end loop;
|
||||
|
||||
pragma Assert (Present (Fin_Context));
|
||||
|
||||
Insert_Action_After (Fin_Context,
|
||||
Make_Implicit_If_Statement (Obj_Decl,
|
||||
Condition =>
|
||||
Make_Op_Ne (Loc,
|
||||
Left_Opnd =>
|
||||
New_Occurrence_Of (Defining_Entity (Hook_Decl), Loc),
|
||||
Right_Opnd => Make_Null (Loc)),
|
||||
|
||||
Then_Statements => New_List (
|
||||
Fin_Call,
|
||||
Hook_Clear)));
|
||||
end if;
|
||||
end Process_Transient_In_Expression;
|
||||
Next (Decl);
|
||||
end loop;
|
||||
end Process_Transients_In_Expression;
|
||||
|
||||
------------------------
|
||||
-- Rewrite_Comparison --
|
||||
|
|
|
|||
|
|
@ -5441,29 +5441,6 @@ package body Exp_Ch6 is
|
|||
is
|
||||
Par : constant Node_Id := Parent (N);
|
||||
|
||||
function Is_Element_Reference (N : Node_Id) return Boolean;
|
||||
-- Determine whether node N denotes a reference to an Ada 2012 container
|
||||
-- element.
|
||||
|
||||
--------------------------
|
||||
-- Is_Element_Reference --
|
||||
--------------------------
|
||||
|
||||
function Is_Element_Reference (N : Node_Id) return Boolean is
|
||||
Ref : constant Node_Id := Original_Node (N);
|
||||
|
||||
begin
|
||||
-- Analysis marks an element reference by setting the generalized
|
||||
-- indexing attribute of an indexed component before the component
|
||||
-- is rewritten into a function call.
|
||||
|
||||
return
|
||||
Nkind (Ref) = N_Indexed_Component
|
||||
and then Present (Generalized_Indexing (Ref));
|
||||
end Is_Element_Reference;
|
||||
|
||||
-- Start of processing for Expand_Ctrl_Function_Call
|
||||
|
||||
begin
|
||||
-- Optimization: if the returned value is returned again, then no need
|
||||
-- to copy/readjust/finalize, we can just pass the value through (see
|
||||
|
|
@ -5500,31 +5477,16 @@ package body Exp_Ch6 is
|
|||
|
||||
Set_Analyzed (N);
|
||||
|
||||
-- Apply the transformation, unless it was already applied manually
|
||||
-- Apply the transformation unless it was already applied earlier. This
|
||||
-- may happen because Remove_Side_Effects can be called during semantic
|
||||
-- analysis, for example from Build_Actual_Subtype_Of_Component. It is
|
||||
-- crucial to avoid creating a reference of reference here, because it
|
||||
-- would not be subsequently recognized by the Is_Finalizable_Transient
|
||||
-- and Requires_Cleanup_Actions predicates.
|
||||
|
||||
if Nkind (Par) /= N_Reference then
|
||||
Remove_Side_Effects (N);
|
||||
end if;
|
||||
|
||||
-- The side effect removal of the function call produced a temporary.
|
||||
-- When the context is a case expression, if expression, or expression
|
||||
-- with actions, the lifetime of the temporary must be extended to match
|
||||
-- that of the context. Otherwise the function result will be finalized
|
||||
-- too early and affect the result of the expression. To prevent this
|
||||
-- unwanted effect, the temporary should not be considered for clean up
|
||||
-- actions by the general finalization machinery.
|
||||
|
||||
-- Exception to this rule are references to Ada 2012 container elements.
|
||||
-- Such references must be finalized at the end of each iteration of the
|
||||
-- related quantified expression, otherwise the container will remain
|
||||
-- busy.
|
||||
|
||||
if Nkind (N) = N_Explicit_Dereference
|
||||
and then Within_Case_Or_If_Expression (N)
|
||||
and then not Is_Element_Reference (N)
|
||||
then
|
||||
Set_Is_Ignored_Transient (Entity (Prefix (N)));
|
||||
end if;
|
||||
end Expand_Ctrl_Function_Call;
|
||||
|
||||
----------------------------------------
|
||||
|
|
|
|||
|
|
@ -1265,7 +1265,7 @@ package body Exp_Ch7 is
|
|||
|
||||
-- Associate the Finalize_Address primitive of the designated type
|
||||
-- with the finalization master of the access type. The designated
|
||||
-- type must be forzen as Finalize_Address is generated when the
|
||||
-- type must be frozen, as Finalize_Address is generated when the
|
||||
-- freeze node is expanded.
|
||||
|
||||
elsif Is_Frozen (Desig_Typ)
|
||||
|
|
@ -2257,19 +2257,19 @@ package body Exp_Ch7 is
|
|||
if For_Package and then Finalize_Storage_Only (Obj_Typ) then
|
||||
null;
|
||||
|
||||
-- Finalization of transient objects are treated separately in
|
||||
-- Finalization of transient objects is treated separately in
|
||||
-- order to handle sensitive cases. These include:
|
||||
|
||||
-- * Conditional expressions
|
||||
-- * Expressions with actions
|
||||
-- * Transient scopes
|
||||
|
||||
-- If one of those contexts has marked the transient object as
|
||||
-- ignored, do not generate finalization actions for it.
|
||||
elsif Is_Finalized_Transient (Obj_Id) then
|
||||
null;
|
||||
|
||||
elsif Is_Finalized_Transient (Obj_Id)
|
||||
or else Is_Ignored_Transient (Obj_Id)
|
||||
then
|
||||
-- Finalization of specific objects is also treated separately
|
||||
|
||||
elsif Is_Ignored_For_Finalization (Obj_Id) then
|
||||
null;
|
||||
|
||||
-- Ignored Ghost objects do not need any cleanup actions
|
||||
|
|
|
|||
|
|
@ -7264,7 +7264,7 @@ package body Exp_Ch9 is
|
|||
-- Generate:
|
||||
-- if K = Ada.Tags.TK_Limited_Tagged
|
||||
-- or else K = Ada.Tags.TK_Tagged
|
||||
-- then
|
||||
-- then
|
||||
-- Lim_Typ_Stmts
|
||||
-- else
|
||||
-- Conc_Typ_Stmts
|
||||
|
|
@ -12740,7 +12740,7 @@ package body Exp_Ch9 is
|
|||
-- Generate:
|
||||
-- if K = Ada.Tags.TK_Limited_Tagged
|
||||
-- or else K = Ada.Tags.TK_Tagged
|
||||
-- then
|
||||
-- then
|
||||
-- Lim_Typ_Stmts
|
||||
-- else
|
||||
-- Conc_Typ_Stmts
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
-- --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
with Aspects; use Aspects;
|
||||
with Atree; use Atree;
|
||||
with Checks; use Checks;
|
||||
with Einfo; use Einfo;
|
||||
|
|
@ -47,6 +48,7 @@ with Sem_Aggr; use Sem_Aggr;
|
|||
with Sem_Aux; use Sem_Aux;
|
||||
with Sem_Ch7; use Sem_Ch7;
|
||||
with Sem_Ch8; use Sem_Ch8;
|
||||
with Sem_Ch13; use Sem_Ch13;
|
||||
with Sem_Prag; use Sem_Prag;
|
||||
with Sem_Res; use Sem_Res;
|
||||
with Sem_Util; use Sem_Util;
|
||||
|
|
@ -64,6 +66,10 @@ package body Exp_SPARK is
|
|||
-- Local Subprograms --
|
||||
-----------------------
|
||||
|
||||
procedure Expand_SPARK_N_Aggregate (N : Node_Id);
|
||||
-- Perform specific expansion of container aggregates, to ensure suitable
|
||||
-- checking of expressions.
|
||||
|
||||
procedure Expand_SPARK_N_Attribute_Reference (N : Node_Id);
|
||||
-- Perform attribute-reference-specific expansion
|
||||
|
||||
|
|
@ -139,6 +145,9 @@ package body Exp_SPARK is
|
|||
when N_Delta_Aggregate =>
|
||||
Expand_SPARK_N_Delta_Aggregate (N);
|
||||
|
||||
when N_Aggregate =>
|
||||
Expand_SPARK_N_Aggregate (N);
|
||||
|
||||
when N_Expanded_Name
|
||||
| N_Identifier
|
||||
=>
|
||||
|
|
@ -418,6 +427,143 @@ package body Exp_SPARK is
|
|||
end if;
|
||||
end Expand_SPARK_Delta_Or_Update;
|
||||
|
||||
------------------------------
|
||||
-- Expand_SPARK_N_Aggregate --
|
||||
------------------------------
|
||||
|
||||
procedure Expand_SPARK_N_Aggregate (N : Node_Id) is
|
||||
|
||||
-- Local subprograms
|
||||
|
||||
procedure Parse_Named_Subp
|
||||
(Subp : Subprogram_Kind_Id;
|
||||
Key_Type : out Type_Kind_Id;
|
||||
Element_Type : out Type_Kind_Id);
|
||||
-- Retrieve key and element types from subprogram for named addition
|
||||
|
||||
procedure Parse_Unnamed_Subp
|
||||
(Subp : Subprogram_Kind_Id;
|
||||
Element_Type : out Type_Kind_Id);
|
||||
-- Retrieve element types from subprogram for unnamed addition
|
||||
|
||||
procedure Wrap_For_Checks (Expr : N_Subexpr_Id; Typ : Type_Kind_Id);
|
||||
-- If Expr might require a range check for conversion to type Typ, set
|
||||
-- Do_Range_Check on Expr. In all cases, wrap Expr in a type conversion
|
||||
-- if Typ is not the type of Expr already, for GNATprove to correctly
|
||||
-- identity the target type for the range check and insert any other
|
||||
-- checks.
|
||||
|
||||
----------------------
|
||||
-- Parse_Named_Subp --
|
||||
----------------------
|
||||
|
||||
procedure Parse_Named_Subp
|
||||
(Subp : Subprogram_Kind_Id;
|
||||
Key_Type : out Type_Kind_Id;
|
||||
Element_Type : out Type_Kind_Id)
|
||||
is
|
||||
Formal : Entity_Id := First_Formal (Subp);
|
||||
begin
|
||||
Next_Formal (Formal);
|
||||
Key_Type := Etype (Formal);
|
||||
Next_Formal (Formal);
|
||||
Element_Type := Etype (Formal);
|
||||
end Parse_Named_Subp;
|
||||
|
||||
------------------------
|
||||
-- Parse_Unnamed_Subp --
|
||||
------------------------
|
||||
|
||||
procedure Parse_Unnamed_Subp
|
||||
(Subp : Subprogram_Kind_Id;
|
||||
Element_Type : out Type_Kind_Id)
|
||||
is
|
||||
Formal : Entity_Id := First_Formal (Subp);
|
||||
begin
|
||||
Next_Formal (Formal);
|
||||
Element_Type := Etype (Formal);
|
||||
end Parse_Unnamed_Subp;
|
||||
|
||||
---------------------
|
||||
-- Wrap_For_Checks --
|
||||
---------------------
|
||||
|
||||
procedure Wrap_For_Checks (Expr : N_Subexpr_Id; Typ : Type_Kind_Id) is
|
||||
begin
|
||||
if Is_Scalar_Type (Typ) then
|
||||
Apply_Scalar_Range_Check (Expr, Typ);
|
||||
end if;
|
||||
|
||||
Convert_To_And_Rewrite (Typ, Expr);
|
||||
end Wrap_For_Checks;
|
||||
|
||||
-- Local variables
|
||||
|
||||
Typ : constant Entity_Id := Etype (N);
|
||||
Asp : constant Node_Id := Find_Value_Of_Aspect (Typ, Aspect_Aggregate);
|
||||
|
||||
Empty_Subp : Node_Id := Empty;
|
||||
Add_Named_Subp : Node_Id := Empty;
|
||||
Add_Unnamed_Subp : Node_Id := Empty;
|
||||
New_Indexed_Subp : Node_Id := Empty;
|
||||
Assign_Indexed_Subp : Node_Id := Empty;
|
||||
Key_Type : Entity_Id;
|
||||
Element_Type : Entity_Id;
|
||||
|
||||
Assocs : constant List_Id := Component_Associations (N);
|
||||
Exprs : constant List_Id := Expressions (N);
|
||||
Choice : Node_Id;
|
||||
Assoc : Node_Id;
|
||||
Expr : Node_Id;
|
||||
|
||||
-- Start of processing for Expand_SPARK_N_Aggregate
|
||||
|
||||
begin
|
||||
if Is_Container_Aggregate (N) then
|
||||
|
||||
Parse_Aspect_Aggregate (Asp,
|
||||
Empty_Subp, Add_Named_Subp, Add_Unnamed_Subp,
|
||||
New_Indexed_Subp, Assign_Indexed_Subp);
|
||||
|
||||
Assoc := First (Assocs);
|
||||
Expr := First (Exprs);
|
||||
|
||||
-- Both lists could be empty as in [] but they can't be both
|
||||
-- non-empty.
|
||||
pragma Assert (not (Present (Assoc) and then Present (Expr)));
|
||||
|
||||
-- Deal with cases supported in GNATprove:
|
||||
-- - named container aggregate which is not an indexed aggregate
|
||||
-- - positional container aggregate
|
||||
|
||||
if Present (Assoc)
|
||||
and then Present (Add_Named_Subp)
|
||||
then
|
||||
Parse_Named_Subp (Entity (Add_Named_Subp), Key_Type, Element_Type);
|
||||
|
||||
while Present (Assoc) loop
|
||||
Choice := First (Choice_List (Assoc));
|
||||
|
||||
while Present (Choice) loop
|
||||
Wrap_For_Checks (Choice, Key_Type);
|
||||
Next (Choice);
|
||||
end loop;
|
||||
|
||||
Wrap_For_Checks (Expression (Assoc), Element_Type);
|
||||
Next (Assoc);
|
||||
end loop;
|
||||
|
||||
elsif Present (Expr) then
|
||||
Parse_Unnamed_Subp (Entity (Add_Unnamed_Subp), Element_Type);
|
||||
|
||||
while Present (Expr) loop
|
||||
Wrap_For_Checks (Expr, Element_Type);
|
||||
Next (Expr);
|
||||
end loop;
|
||||
end if;
|
||||
end if;
|
||||
end Expand_SPARK_N_Aggregate;
|
||||
|
||||
----------------------------------
|
||||
-- Expand_SPARK_N_Freeze_Entity --
|
||||
----------------------------------
|
||||
|
|
|
|||
|
|
@ -13020,19 +13020,19 @@ package body Exp_Util is
|
|||
if Lib_Level and then Finalize_Storage_Only (Obj_Typ) then
|
||||
null;
|
||||
|
||||
-- Finalization of transient objects are treated separately in
|
||||
-- Finalization of transient objects is treated separately in
|
||||
-- order to handle sensitive cases. These include:
|
||||
|
||||
-- * Conditional expressions
|
||||
-- * Expressions with actions
|
||||
-- * Transient scopes
|
||||
|
||||
-- If one of those contexts has marked the transient object as
|
||||
-- ignored, do not generate finalization actions for it.
|
||||
elsif Is_Finalized_Transient (Obj_Id) then
|
||||
null;
|
||||
|
||||
elsif Is_Finalized_Transient (Obj_Id)
|
||||
or else Is_Ignored_Transient (Obj_Id)
|
||||
then
|
||||
-- Finalization of specific objects is also treated separately
|
||||
|
||||
elsif Is_Ignored_For_Finalization (Obj_Id) then
|
||||
null;
|
||||
|
||||
-- Ignored Ghost objects do not need any cleanup actions because
|
||||
|
|
|
|||
|
|
@ -941,9 +941,13 @@ package Exp_Util is
|
|||
function Make_Tag_Assignment_From_Type
|
||||
(Loc : Source_Ptr;
|
||||
Target : Node_Id;
|
||||
Typ : Entity_Id) return Node_Id;
|
||||
Typ : Entity_Id) return Node_Id
|
||||
with
|
||||
Pre => (not Is_Concurrent_Type (Typ));
|
||||
-- Return an assignment of the tag of tagged type Typ to prefix Target,
|
||||
-- which must be a record object of a descendant of Typ.
|
||||
-- which must be a record object of a descendant of Typ. Typ cannot be a
|
||||
-- concurrent type; for concurrent types, the corresponding record types
|
||||
-- should be passed to this function instead.
|
||||
|
||||
function Make_Variant_Comparison
|
||||
(Loc : Source_Ptr;
|
||||
|
|
|
|||
|
|
@ -889,10 +889,6 @@ ada.install-pdf: $(ADA_PDFFILES)
|
|||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
|
||||
done
|
||||
|
||||
ada.html:
|
||||
|
||||
ada.install-html:
|
||||
|
||||
doc/gnat_ugn.dvi: ada/gnat_ugn.texi \
|
||||
$(gcc_docdir)/include/fdl.texi \
|
||||
$(gcc_docdir)/include/gcc-common.texi gcc-vers.texi
|
||||
|
|
@ -917,6 +913,37 @@ doc/gnat_rm.pdf: ada/gnat_rm.texi $(gcc_docdir)/include/fdl.texi \
|
|||
doc/gnat-style.pdf: ada/gnat-style.texi $(gcc_docdir)/include/fdl.texi
|
||||
$(TEXI2PDF) -c -I $(abs_docdir)/include -o $@ $<
|
||||
|
||||
ADA_TEXI_FILES = \
|
||||
ada/gnat_rm.texi \
|
||||
ada/gnat_ugn.texi \
|
||||
$(gcc_docdir)/include/fdl.texi \
|
||||
$(gcc_docdir)/include/gpl_v3.texi \
|
||||
$(gcc_docdir)/include/gcc-common.texi \
|
||||
gcc-vers.texi
|
||||
|
||||
$(build_htmldir)/ada/index.html: $(ADA_TEXI_FILES)
|
||||
$(mkinstalldirs) $(@D)
|
||||
rm -f $(@D)/*
|
||||
$(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/ada -o $(@D) $<
|
||||
|
||||
ada.html: $(build_htmldir)/ada/index.html
|
||||
ada.install-html: $(build_htmldir)/ada
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
|
||||
@for p in $(build_htmldir)/ada; do \
|
||||
if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
|
||||
f=$(html__strip_dir) \
|
||||
if test -d "$$d$$p"; then \
|
||||
echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
|
||||
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
else \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Install hooks:
|
||||
# gnat1 is installed elsewhere as part of $(COMPILERS).
|
||||
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
|| (TYPE_SIZE (gnu_type)
|
||||
&& integer_zerop (TYPE_SIZE (gnu_type))
|
||||
&& !TREE_OVERFLOW (TYPE_SIZE (gnu_type))))
|
||||
&& !Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& !Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& No (gnat_renamed_obj)
|
||||
&& No (Address_Clause (gnat_entity)))
|
||||
gnu_size = bitsize_unit_node;
|
||||
|
|
@ -907,7 +907,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
&& kind != E_Exception
|
||||
&& kind != E_Out_Parameter
|
||||
&& Is_Composite_Type (gnat_type)
|
||||
&& !Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& !Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& !Is_Exported (gnat_entity)
|
||||
&& !imported_p
|
||||
&& No (gnat_renamed_obj)
|
||||
|
|
@ -932,11 +932,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
check_ok_for_atomic_type (gnu_inner, gnat_entity, true);
|
||||
}
|
||||
|
||||
/* If this is an aliased object with an unconstrained array nominal
|
||||
subtype, make a type that includes the template. We will either
|
||||
allocate or create a variable of that type, see below. */
|
||||
if (Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& Is_Array_Type (gnat_und_type)
|
||||
/* If this is an array allocated with its bounds, make a type that
|
||||
includes the template. We will either allocate it or create a
|
||||
variable of that type, see below. */
|
||||
if (Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& !type_annotate_only)
|
||||
{
|
||||
tree gnu_array = gnat_to_gnu_type (Base_Type (gnat_type));
|
||||
|
|
@ -986,7 +985,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
size might be zero at run time, we force at least the unit size. */
|
||||
if (Is_Aliased (gnat_entity)
|
||||
&& Is_Constrained (gnat_type)
|
||||
&& !Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& !Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& Is_Array_Type (gnat_und_type)
|
||||
&& !TREE_CONSTANT (gnu_object_size))
|
||||
gnu_size = size_binop (MAX_EXPR, gnu_object_size, bitsize_unit_node);
|
||||
|
|
@ -1145,12 +1144,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
the entity as indirect reference to the renamed object. */
|
||||
if (Materialize_Entity (gnat_entity))
|
||||
{
|
||||
/* If this is an aliased object with an unconstrained array
|
||||
nominal subtype, we make its type a thin reference, i.e.
|
||||
the reference counterpart of a thin pointer, exactly as
|
||||
we would have done in the non-renaming case below. */
|
||||
if (Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& Is_Array_Type (gnat_und_type)
|
||||
/* If this is an array allocated with its bounds, we make
|
||||
its type a thin reference, the reference counterpart of
|
||||
a thin pointer, exactly as we would have done in the
|
||||
non-renaming case below. */
|
||||
if (Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& !type_annotate_only)
|
||||
{
|
||||
tree gnu_array
|
||||
|
|
@ -1253,8 +1251,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
/* If this is an aliased object with an unconstrained array nominal
|
||||
subtype, then it can overlay only another aliased object with an
|
||||
unconstrained array nominal subtype and compatible template. */
|
||||
if (Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& Is_Array_Type (gnat_und_type)
|
||||
if (Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& !type_annotate_only)
|
||||
{
|
||||
tree rec_type = TREE_TYPE (gnu_type);
|
||||
|
|
@ -1488,14 +1485,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
|
|||
(TREE_TYPE (TYPE_FIELDS (gnu_type))))))
|
||||
static_flag = true;
|
||||
|
||||
/* If this is an aliased object with an unconstrained array nominal
|
||||
subtype, we make its type a thin reference, i.e. the reference
|
||||
counterpart of a thin pointer, so it points to the array part.
|
||||
This is aimed to make it easier for the debugger to decode the
|
||||
object. Note that we have to do it this late because of the
|
||||
couple of allocation adjustments that might be made above. */
|
||||
if (Is_Constr_Subt_For_UN_Aliased (gnat_type)
|
||||
&& Is_Array_Type (gnat_und_type)
|
||||
/* If this is an array allocated with its bounds, we make its type a
|
||||
thin reference, i.e. the reference counterpart of a thin pointer,
|
||||
so that it points to the array part. This is aimed at making it
|
||||
easier for the debugger to decode the object. Note that we have
|
||||
to do it this late because of the couple of allocation adjustments
|
||||
that might be made above. */
|
||||
if (Is_Constr_Array_Subt_With_Bounds (gnat_type)
|
||||
&& !type_annotate_only)
|
||||
{
|
||||
/* In case the object with the template has already been allocated
|
||||
|
|
|
|||
|
|
@ -1322,7 +1322,7 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
|
|||
avoid problematic conversions to the nominal subtype. But remove any
|
||||
padding from the resulting type. */
|
||||
if (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (gnu_result))
|
||||
|| Is_Constr_Subt_For_UN_Aliased (gnat_result_type)
|
||||
|| Is_Constr_Array_Subt_With_Bounds (gnat_result_type)
|
||||
|| (Ekind (gnat_entity) == E_Constant
|
||||
&& Present (Full_View (gnat_entity))
|
||||
&& Has_Discriminants (gnat_result_type)
|
||||
|
|
@ -5039,16 +5039,14 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
|
|||
gnu_actual = convert (get_unpadded_type (Etype (gnat_actual)),
|
||||
gnu_actual);
|
||||
|
||||
/* If we have the constructed subtype of an aliased object
|
||||
with an unconstrained nominal subtype, the type of the
|
||||
actual includes the template, although it is formally
|
||||
constrained. So we need to convert it back to the real
|
||||
constructed subtype to retrieve the constrained part
|
||||
and takes its address. */
|
||||
/* If it is the constructed subtype of an array allocated with
|
||||
its bounds, the type of the actual includes the template,
|
||||
although it is formally constrained. So we need to convert
|
||||
it back to the real constructed subtype to retrieve the
|
||||
constrained part and takes its address. */
|
||||
if (TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE
|
||||
&& TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (gnu_actual))
|
||||
&& Is_Constr_Subt_For_UN_Aliased (Etype (gnat_actual))
|
||||
&& Is_Array_Type (Underlying_Type (Etype (gnat_actual))))
|
||||
&& Is_Constr_Array_Subt_With_Bounds (Etype (gnat_actual)))
|
||||
gnu_actual = convert (gnu_actual_type, gnu_actual);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,34 @@ static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] =
|
|||
{ NULL, false, false, false },
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
|
||||
{
|
||||
{ "noinline", true, true, true },
|
||||
{ "target_clones", true, true, true },
|
||||
{ NULL, false, false, false },
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
|
||||
{
|
||||
{ "always_inline", true, true, true },
|
||||
{ NULL, false, false, false },
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_target_exclusions[] =
|
||||
{
|
||||
{ "target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
|
||||
TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE },
|
||||
{ NULL, false, false, false },
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_target_clones_exclusions[] =
|
||||
{
|
||||
{ "always_inline", true, true, true },
|
||||
{ "target", TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE,
|
||||
TARGET_HAS_FMV_TARGET_ATTRIBUTE },
|
||||
{ NULL, false, false, false },
|
||||
};
|
||||
|
||||
/* Fake handler for attributes we don't properly support, typically because
|
||||
they'd require dragging a lot of the common-c front-end circuitry. */
|
||||
static tree fake_attribute_handler (tree *, tree, tree, int, bool *);
|
||||
|
|
@ -166,7 +194,7 @@ static const attribute_spec gnat_internal_attributes[] =
|
|||
{ "strub", 0, 1, false, true, false, true,
|
||||
handle_strub_attribute, NULL },
|
||||
{ "noinline", 0, 0, true, false, false, false,
|
||||
handle_noinline_attribute, NULL },
|
||||
handle_noinline_attribute, attr_noinline_exclusions },
|
||||
{ "noclone", 0, 0, true, false, false, false,
|
||||
handle_noclone_attribute, NULL },
|
||||
{ "no_icf", 0, 0, true, false, false, false,
|
||||
|
|
@ -176,7 +204,7 @@ static const attribute_spec gnat_internal_attributes[] =
|
|||
{ "leaf", 0, 0, true, false, false, false,
|
||||
handle_leaf_attribute, NULL },
|
||||
{ "always_inline",0, 0, true, false, false, false,
|
||||
handle_always_inline_attribute, NULL },
|
||||
handle_always_inline_attribute, attr_always_inline_exclusions },
|
||||
{ "malloc", 0, 0, true, false, false, false,
|
||||
handle_malloc_attribute, NULL },
|
||||
{ "type generic", 0, 0, false, true, true, false,
|
||||
|
|
@ -193,9 +221,9 @@ static const attribute_spec gnat_internal_attributes[] =
|
|||
{ "simd", 0, 1, true, false, false, false,
|
||||
handle_simd_attribute, NULL },
|
||||
{ "target", 1, -1, true, false, false, false,
|
||||
handle_target_attribute, NULL },
|
||||
handle_target_attribute, attr_target_exclusions },
|
||||
{ "target_clones",1, -1, true, false, false, false,
|
||||
handle_target_clones_attribute, NULL },
|
||||
handle_target_clones_attribute, attr_target_clones_exclusions },
|
||||
|
||||
{ "vector_size", 1, 1, false, true, false, false,
|
||||
handle_vector_size_attribute, NULL },
|
||||
|
|
@ -6826,16 +6854,7 @@ handle_noinline_attribute (tree *node, tree name,
|
|||
int ARG_UNUSED (flags), bool *no_add_attrs)
|
||||
{
|
||||
if (TREE_CODE (*node) == FUNCTION_DECL)
|
||||
{
|
||||
if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with attribute %qs", name, "always_inline");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else
|
||||
DECL_UNINLINABLE (*node) = 1;
|
||||
}
|
||||
DECL_UNINLINABLE (*node) = 1;
|
||||
else
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
|
|
@ -7134,12 +7153,6 @@ handle_target_attribute (tree *node, tree name, tree args, int flags,
|
|||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "target_clones");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (!targetm.target_option.valid_attribute_p (*node, name, args, flags))
|
||||
*no_add_attrs = true;
|
||||
|
||||
|
|
@ -7167,23 +7180,8 @@ handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args),
|
|||
{
|
||||
/* Ensure we have a function type. */
|
||||
if (TREE_CODE (*node) == FUNCTION_DECL)
|
||||
{
|
||||
if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "always_inline");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (lookup_attribute ("target", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "target");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else
|
||||
/* Do not inline functions with multiple clone targets. */
|
||||
DECL_UNINLINABLE (*node) = 1;
|
||||
}
|
||||
/* Do not inline functions with multiple clone targets. */
|
||||
DECL_UNINLINABLE (*node) = 1;
|
||||
else
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ package Gen_IL.Fields is
|
|||
Acts_As_Spec,
|
||||
Actual_Designated_Subtype,
|
||||
Address_Warning_Posted,
|
||||
Aggregate_Bounds,
|
||||
Aggregate_Bounds_Or_Ancestor_Type,
|
||||
Aliased_Present,
|
||||
All_Others,
|
||||
All_Present,
|
||||
|
|
@ -686,8 +686,8 @@ package Gen_IL.Fields is
|
|||
Is_Compilation_Unit,
|
||||
Is_Completely_Hidden,
|
||||
Is_Concurrent_Record_Type,
|
||||
Is_Constr_Array_Subt_With_Bounds,
|
||||
Is_Constr_Subt_For_U_Nominal,
|
||||
Is_Constr_Subt_For_UN_Aliased,
|
||||
Is_Constrained,
|
||||
Is_Constructor,
|
||||
Is_Controlled_Active,
|
||||
|
|
@ -721,8 +721,8 @@ package Gen_IL.Fields is
|
|||
Is_Hidden,
|
||||
Is_Hidden_Non_Overridden_Subpgm,
|
||||
Is_Hidden_Open_Scope,
|
||||
Is_Ignored_For_Finalization,
|
||||
Is_Ignored_Ghost_Entity,
|
||||
Is_Ignored_Transient,
|
||||
Is_Immediately_Visible,
|
||||
Is_Implementation_Defined,
|
||||
Is_Imported,
|
||||
|
|
|
|||
|
|
@ -129,8 +129,8 @@ begin -- Gen_IL.Gen.Gen_Entities
|
|||
Sm (Is_Class_Wide_Equivalent_Type, Flag),
|
||||
Sm (Is_Compilation_Unit, Flag),
|
||||
Sm (Is_Concurrent_Record_Type, Flag),
|
||||
Sm (Is_Constr_Array_Subt_With_Bounds, Flag),
|
||||
Sm (Is_Constr_Subt_For_U_Nominal, Flag),
|
||||
Sm (Is_Constr_Subt_For_UN_Aliased, Flag),
|
||||
Sm (Is_Constrained, Flag),
|
||||
Sm (Is_Constructor, Flag),
|
||||
Sm (Is_Controlled_Active, Flag, Base_Type_Only),
|
||||
|
|
@ -337,7 +337,7 @@ begin -- Gen_IL.Gen.Gen_Entities
|
|||
Sm (Esize, Uint),
|
||||
Sm (Interface_Name, Node_Id),
|
||||
Sm (Is_Finalized_Transient, Flag),
|
||||
Sm (Is_Ignored_Transient, Flag),
|
||||
Sm (Is_Ignored_For_Finalization, Flag),
|
||||
Sm (Linker_Section_Pragma, Node_Id),
|
||||
Sm (Related_Expression, Node_Id),
|
||||
Sm (Status_Flag_Or_Transient_Decl, Node_Id)));
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
|
|||
Sy (Is_Parenthesis_Aggregate, Flag),
|
||||
Sy (Is_Homogeneous_Aggregate, Flag),
|
||||
Sy (Is_Enum_Array_Aggregate, Flag),
|
||||
Sm (Aggregate_Bounds, Node_Id),
|
||||
Sm (Aggregate_Bounds_Or_Ancestor_Type, Node_Id),
|
||||
Sm (Entity_Or_Associated_Node, Node_Id), -- just Associated_Node
|
||||
Sm (Compile_Time_Known_Aggregate, Flag),
|
||||
Sm (Expansion_Delayed, Flag),
|
||||
|
|
|
|||
|
|
@ -289,8 +289,6 @@ package body Gen_IL.Internals is
|
|||
return "Has_SP_Choice";
|
||||
when Ignore_SPARK_Mode_Pragmas =>
|
||||
return "Ignore_SPARK_Mode_Pragmas";
|
||||
when Is_Constr_Subt_For_UN_Aliased =>
|
||||
return "Is_Constr_Subt_For_UN_Aliased";
|
||||
when Is_CPP_Class =>
|
||||
return "Is_CPP_Class";
|
||||
when Is_CUDA_Kernel =>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
@setfilename gnat-style.info
|
||||
@documentencoding UTF-8
|
||||
@ifinfo
|
||||
@*Generated by Sphinx 5.3.0.@*
|
||||
@*Generated by Sphinx 4.3.2.@*
|
||||
@end ifinfo
|
||||
@settitle GNAT Coding Style A Guide for GNAT Developers
|
||||
@defindex ge
|
||||
|
|
@ -15,11 +15,13 @@
|
|||
* gnat-style: (gnat-style.info). gnat-style
|
||||
@end direntry
|
||||
|
||||
@definfoenclose strong,`,'
|
||||
@definfoenclose emph,`,'
|
||||
@c %**end of header
|
||||
|
||||
@copying
|
||||
@quotation
|
||||
GNAT Coding Style: A Guide for GNAT Developers , Oct 26, 2023
|
||||
GNAT Coding Style: A Guide for GNAT Developers , Dec 14, 2023
|
||||
|
||||
AdaCore
|
||||
|
||||
|
|
@ -253,7 +255,7 @@ When declarations are commented with ‘hanging’ comments, i.e.
|
|||
comments after the declaration, there is no blank line before the
|
||||
comment, and if it is absolutely necessary to have blank lines within
|
||||
the comments, e.g. to make paragraph separations within a single comment,
|
||||
these blank lines `do' have a @code{--} (unlike the
|
||||
these blank lines @emph{do} have a @code{--} (unlike the
|
||||
normal rule, which is to use entirely blank lines for separating
|
||||
comment paragraphs). The comment starts at same level of indentation
|
||||
as code it is commenting.
|
||||
|
|
@ -302,12 +304,12 @@ Other_Id := 6; -- Second comment
|
|||
@end example
|
||||
|
||||
@item
|
||||
Short comments that fit on a single line are `not' ended with a
|
||||
Short comments that fit on a single line are @emph{not} ended with a
|
||||
period. Comments taking more than a line are punctuated in the normal
|
||||
manner.
|
||||
|
||||
@item
|
||||
Comments should focus on `why' instead of `what'.
|
||||
Comments should focus on @emph{why} instead of @emph{what}.
|
||||
Descriptions of what subprograms do go with the specification.
|
||||
|
||||
@item
|
||||
|
|
@ -317,7 +319,7 @@ depend on the names of things. The names are supplementary, not
|
|||
sufficient, as comments.
|
||||
|
||||
@item
|
||||
`Do not' put two spaces after periods in comments.
|
||||
@emph{Do not} put two spaces after periods in comments.
|
||||
@end itemize
|
||||
|
||||
@node Declarations and Types,Expressions and Names,Lexical Elements,Top
|
||||
|
|
@ -956,7 +958,7 @@ Copyright 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc
|
|||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
`Preamble'
|
||||
@strong{Preamble}
|
||||
|
||||
The purpose of this License is to make a manual, textbook, or other
|
||||
functional and useful document “free” in the sense of freedom: to
|
||||
|
|
@ -979,23 +981,23 @@ it can be used for any textual work, regardless of subject matter or
|
|||
whether it is published as a printed book. We recommend this License
|
||||
principally for works whose purpose is instruction or reference.
|
||||
|
||||
`1. APPLICABILITY AND DEFINITIONS'
|
||||
@strong{1. APPLICABILITY AND DEFINITIONS}
|
||||
|
||||
This License applies to any manual or other work, in any medium, that
|
||||
contains a notice placed by the copyright holder saying it can be
|
||||
distributed under the terms of this License. Such a notice grants a
|
||||
world-wide, royalty-free license, unlimited in duration, to use that
|
||||
work under the conditions stated herein. The `Document', below,
|
||||
work under the conditions stated herein. The @strong{Document}, below,
|
||||
refers to any such manual or work. Any member of the public is a
|
||||
licensee, and is addressed as “`you'”. You accept the license if you
|
||||
licensee, and is addressed as “@strong{you}”. You accept the license if you
|
||||
copy, modify or distribute the work in a way requiring permission
|
||||
under copyright law.
|
||||
|
||||
A “`Modified Version'” of the Document means any work containing the
|
||||
A “@strong{Modified Version}” of the Document means any work containing the
|
||||
Document or a portion of it, either copied verbatim, or with
|
||||
modifications and/or translated into another language.
|
||||
|
||||
A “`Secondary Section'” is a named appendix or a front-matter section of
|
||||
A “@strong{Secondary Section}” is a named appendix or a front-matter section of
|
||||
the Document that deals exclusively with the relationship of the
|
||||
publishers or authors of the Document to the Document’s overall subject
|
||||
(or to related matters) and contains nothing that could fall directly
|
||||
|
|
@ -1006,7 +1008,7 @@ connection with the subject or with related matters, or of legal,
|
|||
commercial, philosophical, ethical or political position regarding
|
||||
them.
|
||||
|
||||
The “`Invariant Sections'” are certain Secondary Sections whose titles
|
||||
The “@strong{Invariant Sections}” are certain Secondary Sections whose titles
|
||||
are designated, as being those of Invariant Sections, in the notice
|
||||
that says that the Document is released under this License. If a
|
||||
section does not fit the above definition of Secondary then it is not
|
||||
|
|
@ -1014,12 +1016,12 @@ allowed to be designated as Invariant. The Document may contain zero
|
|||
Invariant Sections. If the Document does not identify any Invariant
|
||||
Sections then there are none.
|
||||
|
||||
The “`Cover Texts'” are certain short passages of text that are listed,
|
||||
The “@strong{Cover Texts}” are certain short passages of text that are listed,
|
||||
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
|
||||
the Document is released under this License. A Front-Cover Text may
|
||||
be at most 5 words, and a Back-Cover Text may be at most 25 words.
|
||||
|
||||
A “`Transparent'” copy of the Document means a machine-readable copy,
|
||||
A “@strong{Transparent}” copy of the Document means a machine-readable copy,
|
||||
represented in a format whose specification is available to the
|
||||
general public, that is suitable for revising the document
|
||||
straightforwardly with generic text editors or (for images composed of
|
||||
|
|
@ -1030,7 +1032,7 @@ to text formatters. A copy made in an otherwise Transparent file
|
|||
format whose markup, or absence of markup, has been arranged to thwart
|
||||
or discourage subsequent modification by readers is not Transparent.
|
||||
An image format is not Transparent if used for any substantial amount
|
||||
of text. A copy that is not “Transparent” is called `Opaque'.
|
||||
of text. A copy that is not “Transparent” is called @strong{Opaque}.
|
||||
|
||||
Examples of suitable formats for Transparent copies include plain
|
||||
ASCII without markup, Texinfo input format, LaTeX input format, SGML
|
||||
|
|
@ -1043,22 +1045,22 @@ processing tools are not generally available, and the
|
|||
machine-generated HTML, PostScript or PDF produced by some word
|
||||
processors for output purposes only.
|
||||
|
||||
The “`Title Page'” means, for a printed book, the title page itself,
|
||||
The “@strong{Title Page}” means, for a printed book, the title page itself,
|
||||
plus such following pages as are needed to hold, legibly, the material
|
||||
this License requires to appear in the title page. For works in
|
||||
formats which do not have any title page as such, “Title Page” means
|
||||
the text near the most prominent appearance of the work’s title,
|
||||
preceding the beginning of the body of the text.
|
||||
|
||||
The “`publisher'” means any person or entity that distributes
|
||||
The “@strong{publisher}” means any person or entity that distributes
|
||||
copies of the Document to the public.
|
||||
|
||||
A section “`Entitled XYZ'” means a named subunit of the Document whose
|
||||
A section “@strong{Entitled XYZ}” means a named subunit of the Document whose
|
||||
title either is precisely XYZ or contains XYZ in parentheses following
|
||||
text that translates XYZ in another language. (Here XYZ stands for a
|
||||
specific section name mentioned below, such as “`Acknowledgements'”,
|
||||
“`Dedications'”, “`Endorsements'”, or “`History'”.)
|
||||
To “`Preserve the Title'”
|
||||
specific section name mentioned below, such as “@strong{Acknowledgements}”,
|
||||
“@strong{Dedications}”, “@strong{Endorsements}”, or “@strong{History}”.)
|
||||
To “@strong{Preserve the Title}”
|
||||
of such a section when you modify the Document means that it remains a
|
||||
section “Entitled XYZ” according to this definition.
|
||||
|
||||
|
|
@ -1069,7 +1071,7 @@ License, but only as regards disclaiming warranties: any other
|
|||
implication that these Warranty Disclaimers may have is void and has
|
||||
no effect on the meaning of this License.
|
||||
|
||||
`2. VERBATIM COPYING'
|
||||
@strong{2. VERBATIM COPYING}
|
||||
|
||||
You may copy and distribute the Document in any medium, either
|
||||
commercially or noncommercially, provided that this License, the
|
||||
|
|
@ -1084,7 +1086,7 @@ number of copies you must also follow the conditions in section 3.
|
|||
You may also lend copies, under the same conditions stated above, and
|
||||
you may publicly display copies.
|
||||
|
||||
`3. COPYING IN QUANTITY'
|
||||
@strong{3. COPYING IN QUANTITY}
|
||||
|
||||
If you publish printed copies (or copies in media that commonly have
|
||||
printed covers) of the Document, numbering more than 100, and the
|
||||
|
|
@ -1121,7 +1123,7 @@ It is requested, but not required, that you contact the authors of the
|
|||
Document well before redistributing any large number of copies, to give
|
||||
them a chance to provide you with an updated version of the Document.
|
||||
|
||||
`4. MODIFICATIONS'
|
||||
@strong{4. MODIFICATIONS}
|
||||
|
||||
You may copy and distribute a Modified Version of the Document under
|
||||
the conditions of sections 2 and 3 above, provided that you release
|
||||
|
|
@ -1238,7 +1240,7 @@ The author(s) and publisher(s) of the Document do not by this License
|
|||
give permission to use their names for publicity for or to assert or
|
||||
imply endorsement of any Modified Version.
|
||||
|
||||
`5. COMBINING DOCUMENTS'
|
||||
@strong{5. COMBINING DOCUMENTS}
|
||||
|
||||
You may combine the Document with other documents released under this
|
||||
License, under the terms defined in section 4 above for modified
|
||||
|
|
@ -1262,7 +1264,7 @@ in the various original documents, forming one section Entitled
|
|||
and any sections Entitled “Dedications”. You must delete all sections
|
||||
Entitled “Endorsements”.
|
||||
|
||||
`6. COLLECTIONS OF DOCUMENTS'
|
||||
@strong{6. COLLECTIONS OF DOCUMENTS}
|
||||
|
||||
You may make a collection consisting of the Document and other documents
|
||||
released under this License, and replace the individual copies of this
|
||||
|
|
@ -1275,7 +1277,7 @@ it individually under this License, provided you insert a copy of this
|
|||
License into the extracted document, and follow this License in all
|
||||
other respects regarding verbatim copying of that document.
|
||||
|
||||
`7. AGGREGATION WITH INDEPENDENT WORKS'
|
||||
@strong{7. AGGREGATION WITH INDEPENDENT WORKS}
|
||||
|
||||
A compilation of the Document or its derivatives with other separate
|
||||
and independent documents or works, in or on a volume of a storage or
|
||||
|
|
@ -1294,7 +1296,7 @@ electronic equivalent of covers if the Document is in electronic form.
|
|||
Otherwise they must appear on printed covers that bracket the whole
|
||||
aggregate.
|
||||
|
||||
`8. TRANSLATION'
|
||||
@strong{8. TRANSLATION}
|
||||
|
||||
Translation is considered a kind of modification, so you may
|
||||
distribute translations of the Document under the terms of section 4.
|
||||
|
|
@ -1314,7 +1316,7 @@ If a section in the Document is Entitled “Acknowledgements”,
|
|||
its Title (section 1) will typically require changing the actual
|
||||
title.
|
||||
|
||||
`9. TERMINATION'
|
||||
@strong{9. TERMINATION}
|
||||
|
||||
You may not copy, modify, sublicense, or distribute the Document
|
||||
except as expressly provided under this License. Any attempt
|
||||
|
|
@ -1341,7 +1343,7 @@ this License. If your rights have been terminated and not permanently
|
|||
reinstated, receipt of a copy of some or all of the same material does
|
||||
not give you any rights to use it.
|
||||
|
||||
`10. FUTURE REVISIONS OF THIS LICENSE'
|
||||
@strong{10. FUTURE REVISIONS OF THIS LICENSE}
|
||||
|
||||
The Free Software Foundation may publish new, revised versions
|
||||
of the GNU Free Documentation License from time to time. Such new
|
||||
|
|
@ -1362,7 +1364,7 @@ License can be used, that proxy’s public statement of acceptance of a
|
|||
version permanently authorizes you to choose that version for the
|
||||
Document.
|
||||
|
||||
`11. RELICENSING'
|
||||
@strong{11. RELICENSING}
|
||||
|
||||
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any
|
||||
World Wide Web server that publishes copyrightable works and also
|
||||
|
|
@ -1391,7 +1393,7 @@ The operator of an MMC Site may republish an MMC contained in the site
|
|||
under CC-BY-SA on the same site at any time before August 1, 2009,
|
||||
provided the MMC is eligible for relicensing.
|
||||
|
||||
`ADDENDUM: How to use this License for your documents'
|
||||
@strong{ADDENDUM: How to use this License for your documents}
|
||||
|
||||
To use this License in a document you have written, include a copy of
|
||||
the License in the document and put the following copyright and
|
||||
|
|
|
|||
1078
gcc/ada/gnat_rm.texi
1078
gcc/ada/gnat_rm.texi
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -77,16 +77,11 @@ package body Ada.Command_Line is
|
|||
|
||||
function Argument_Count return Natural is
|
||||
begin
|
||||
if not Initialized then
|
||||
-- RM A.15 (11)
|
||||
return 0;
|
||||
end if;
|
||||
|
||||
if Remove_Args = null then
|
||||
return Arg_Count - 1;
|
||||
else
|
||||
return Remove_Count;
|
||||
end if;
|
||||
return
|
||||
(if not Initialized then 0 -- RM A.15 (11)
|
||||
elsif Remove_Args = null then Arg_Count - 1
|
||||
else Remove_Count
|
||||
);
|
||||
end Argument_Count;
|
||||
|
||||
-----------------
|
||||
|
|
@ -107,6 +102,8 @@ package body Ada.Command_Line is
|
|||
|
||||
function Command_Name return String is
|
||||
begin
|
||||
pragma Annotate (Gnatcheck, Exempt_On, "Improper_Returns",
|
||||
"early returns for performance");
|
||||
if not Initialized then
|
||||
return "";
|
||||
end if;
|
||||
|
|
@ -118,6 +115,7 @@ package body Ada.Command_Line is
|
|||
Fill_Arg (Arg'Address, 0);
|
||||
return Arg;
|
||||
end;
|
||||
pragma Annotate (Gnatcheck, Exempt_Off, "Improper_Returns");
|
||||
end Command_Name;
|
||||
|
||||
end Ada.Command_Line;
|
||||
|
|
|
|||
|
|
@ -346,11 +346,13 @@ is
|
|||
end Value;
|
||||
|
||||
function Value (Item : chars_ptr; Length : size_t) return String is
|
||||
Result : char_array (0 .. Length);
|
||||
Result : String (1 .. Natural (Length));
|
||||
C : char;
|
||||
|
||||
begin
|
||||
pragma Annotate (Gnatcheck, Exempt_On, "Improper_Returns",
|
||||
"early returns for performance");
|
||||
|
||||
-- As per AI-00177, this is equivalent to:
|
||||
|
||||
-- To_Ada (Value (Item, Length) & nul);
|
||||
|
|
@ -359,16 +361,17 @@ is
|
|||
raise Dereference_Error;
|
||||
end if;
|
||||
|
||||
for J in 0 .. Length - 1 loop
|
||||
Result (J) := Peek (Item + J);
|
||||
for J in Result'Range loop
|
||||
C := Peek (Item + size_t (J - 1));
|
||||
|
||||
if Result (J) = nul then
|
||||
return To_Ada (Result (0 .. J));
|
||||
if C = nul then
|
||||
return Result (1 .. J - 1);
|
||||
else
|
||||
Result (J) := To_Ada (C);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
Result (Length) := nul;
|
||||
return To_Ada (Result);
|
||||
return Result;
|
||||
|
||||
pragma Annotate (Gnatcheck, Exempt_Off, "Improper_Returns");
|
||||
end Value;
|
||||
|
|
|
|||
|
|
@ -449,7 +449,6 @@ package System.Rident is
|
|||
No_Asynchronous_Control => True,
|
||||
No_Dynamic_Attachment => True,
|
||||
No_Dynamic_CPU_Assignment => True,
|
||||
No_Dynamic_Priorities => True,
|
||||
No_Local_Protected_Objects => True,
|
||||
No_Protected_Type_Allocators => True,
|
||||
No_Requeue_Statements => True,
|
||||
|
|
|
|||
|
|
@ -3270,13 +3270,13 @@ package body Sem_Aggr is
|
|||
(Iterator_Specification (Comp)));
|
||||
end if;
|
||||
|
||||
-- Key expression must have the type of the key. We analyze
|
||||
-- Key expression must have the type of the key. We preanalyze
|
||||
-- a copy of the original expression, because it will be
|
||||
-- reanalyzed and copied as needed during expansion of the
|
||||
-- corresponding loop.
|
||||
|
||||
Key_Expr := Key_Expression (Comp);
|
||||
Analyze_And_Resolve (New_Copy_Tree (Key_Expr), Key_Type);
|
||||
Preanalyze_And_Resolve (New_Copy_Tree (Key_Expr), Key_Type);
|
||||
End_Scope;
|
||||
|
||||
Typ := Key_Type;
|
||||
|
|
@ -3436,11 +3436,25 @@ package body Sem_Aggr is
|
|||
Key_Type : constant Entity_Id := Etype (Next_Formal (Container));
|
||||
Elmt_Type : constant Entity_Id :=
|
||||
Etype (Next_Formal (Next_Formal (Container)));
|
||||
Comp : Node_Id;
|
||||
Choice : Node_Id;
|
||||
|
||||
Comp_Assocs : constant List_Id := Component_Associations (N);
|
||||
Comp : Node_Id;
|
||||
Choice : Node_Id;
|
||||
|
||||
begin
|
||||
Comp := First (Component_Associations (N));
|
||||
-- In the Add_Named case, the aggregate must consist of named
|
||||
-- associations (Add_Unnnamed is not allowed), so we issue an
|
||||
-- error if there are positional associations.
|
||||
|
||||
if not Present (Comp_Assocs)
|
||||
and then Present (Expressions (N))
|
||||
then
|
||||
Error_Msg_N ("container aggregate must be "
|
||||
& "named, not positional", N);
|
||||
return;
|
||||
end if;
|
||||
|
||||
Comp := First (Comp_Assocs);
|
||||
while Present (Comp) loop
|
||||
if Nkind (Comp) = N_Component_Association then
|
||||
Choice := First (Choices (Comp));
|
||||
|
|
@ -5644,18 +5658,14 @@ package body Sem_Aggr is
|
|||
Parent_Typ := Etype (Parent_Typ);
|
||||
|
||||
-- Check whether a private parent requires the use of
|
||||
-- an extension aggregate. This test does not apply in
|
||||
-- an instantiation: if the generic unit is legal so is
|
||||
-- the instance.
|
||||
-- an extension aggregate.
|
||||
|
||||
if Nkind (Parent (Base_Type (Parent_Typ))) =
|
||||
N_Private_Type_Declaration
|
||||
or else Nkind (Parent (Base_Type (Parent_Typ))) =
|
||||
N_Private_Extension_Declaration
|
||||
then
|
||||
if Nkind (N) /= N_Extension_Aggregate
|
||||
and then not In_Instance
|
||||
then
|
||||
if Nkind (N) /= N_Extension_Aggregate then
|
||||
Error_Msg_NE
|
||||
("type of aggregate has private ancestor&!",
|
||||
N, Parent_Typ);
|
||||
|
|
|
|||
|
|
@ -4529,7 +4529,7 @@ package body Sem_Ch10 is
|
|||
then
|
||||
-- If the unit is an ancestor of the current one, it is the
|
||||
-- case of a private limited with clause on a child unit, and
|
||||
-- the compilation of one of its descendants, In that case the
|
||||
-- the compilation of one of its descendants, in that case the
|
||||
-- limited view is errelevant.
|
||||
|
||||
if Limited_Present (Item) then
|
||||
|
|
|
|||
|
|
@ -7059,10 +7059,14 @@ package body Sem_Ch12 is
|
|||
end if;
|
||||
end Check_Actual_Type;
|
||||
|
||||
-- Local variables
|
||||
|
||||
Astype : Entity_Id;
|
||||
E : Entity_Id;
|
||||
Formal : Node_Id;
|
||||
|
||||
-- Start of processing for Check_Generic_Actuals
|
||||
|
||||
begin
|
||||
E := First_Entity (Instance);
|
||||
while Present (E) loop
|
||||
|
|
@ -7234,7 +7238,7 @@ package body Sem_Ch12 is
|
|||
Loc : constant Source_Ptr := Sloc (Gen_Id);
|
||||
Gen_Par : Entity_Id := Empty;
|
||||
E : Entity_Id;
|
||||
Inst_Par : Entity_Id;
|
||||
Inst_Par : Entity_Id := Empty;
|
||||
S : Node_Id;
|
||||
|
||||
function Find_Generic_Child
|
||||
|
|
@ -7440,16 +7444,90 @@ package body Sem_Ch12 is
|
|||
-- the instance of Gpar, so this is illegal. The test below
|
||||
-- recognizes this particular case.
|
||||
|
||||
if Is_Child_Unit (E)
|
||||
and then not Comes_From_Source (Entity (Prefix (Gen_Id)))
|
||||
and then (not In_Instance
|
||||
or else Nkind (Parent (Parent (Gen_Id))) =
|
||||
N_Compilation_Unit)
|
||||
then
|
||||
Error_Msg_N
|
||||
("prefix of generic child unit must be instance of parent",
|
||||
Gen_Id);
|
||||
end if;
|
||||
declare
|
||||
-- We want to reject the final instantiation in
|
||||
-- generic package G1 is end G1;
|
||||
-- generic package G1.G2 is end G1.G2;
|
||||
-- with G1; package I1 is new G1;
|
||||
-- with G1.G2; package I1.I2 is new G1.G2;
|
||||
-- because the use of G1.G2 should instead be either
|
||||
-- I1.G2 or simply G2. However, the tree that is built
|
||||
-- in this case is wrong. In the expanded copy
|
||||
-- of G2, we need (and therefore generate) a renaming
|
||||
-- package G1 renames I1;
|
||||
-- but this renaming should not participate in resolving
|
||||
-- this occurrence of the name "G1.G2"; unfortunately,
|
||||
-- it does. Rather than correct this error, we compensate
|
||||
-- for it in this function.
|
||||
--
|
||||
-- We also perform another adjustment here. If we are
|
||||
-- currently inside a generic package, then that
|
||||
-- generic package needs to be treated as a package.
|
||||
-- For example, if a generic Aaa declares a nested generic
|
||||
-- Bbb (perhaps as a child unit) then Aaa can also legally
|
||||
-- declare an instance of Aaa.Bbb.
|
||||
|
||||
function Adjusted_Inst_Par_Ekind return Entity_Kind;
|
||||
|
||||
-----------------------------
|
||||
-- Adjusted_Inst_Par_Ekind --
|
||||
-----------------------------
|
||||
|
||||
function Adjusted_Inst_Par_Ekind return Entity_Kind is
|
||||
Prefix_Entity : Entity_Id;
|
||||
Inst_Par_GP : Node_Id;
|
||||
Inst_Par_Parent : Node_Id := Parent (Inst_Par);
|
||||
begin
|
||||
if Nkind (Inst_Par_Parent) = N_Defining_Program_Unit_Name
|
||||
then
|
||||
Inst_Par_Parent := Parent (Inst_Par_Parent);
|
||||
end if;
|
||||
|
||||
Inst_Par_GP := Generic_Parent (Inst_Par_Parent);
|
||||
|
||||
if Nkind (Gen_Id) = N_Expanded_Name
|
||||
and then Present (Inst_Par_GP)
|
||||
and then Ekind (Inst_Par_GP) = E_Generic_Package
|
||||
then
|
||||
Prefix_Entity := Entity (Prefix (Gen_Id));
|
||||
|
||||
if Present (Prefix_Entity)
|
||||
and then not Comes_From_Source (Prefix_Entity)
|
||||
and then Nkind (Parent (Prefix_Entity)) =
|
||||
N_Package_Renaming_Declaration
|
||||
and then Chars (Prefix_Entity) = Chars (Inst_Par_GP)
|
||||
then
|
||||
return E_Generic_Package;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if Ekind (Inst_Par) = E_Generic_Package
|
||||
and then In_Open_Scopes (Inst_Par)
|
||||
then
|
||||
-- If we are inside a generic package then
|
||||
-- treat it as a package.
|
||||
return E_Package;
|
||||
end if;
|
||||
|
||||
-- The usual path
|
||||
return Ekind (Inst_Par);
|
||||
end Adjusted_Inst_Par_Ekind;
|
||||
|
||||
begin
|
||||
if Is_Child_Unit (E)
|
||||
and then (No (Inst_Par)
|
||||
or else Adjusted_Inst_Par_Ekind =
|
||||
E_Generic_Package)
|
||||
and then (not In_Instance
|
||||
or else Nkind (Parent (Parent (Gen_Id))) =
|
||||
N_Compilation_Unit)
|
||||
then
|
||||
Error_Msg_N
|
||||
("prefix of generic child unit must be " &
|
||||
"instance of parent",
|
||||
Gen_Id);
|
||||
end if;
|
||||
end;
|
||||
|
||||
if not In_Open_Scopes (Inst_Par)
|
||||
and then Nkind (Parent (Gen_Id)) not in
|
||||
|
|
@ -8421,38 +8499,48 @@ package body Sem_Ch12 is
|
|||
Set_Associated_Node (N, New_N);
|
||||
|
||||
else
|
||||
if Present (Get_Associated_Node (N))
|
||||
and then Nkind (Get_Associated_Node (N)) = Nkind (N)
|
||||
then
|
||||
-- In the generic the aggregate has some composite type. If at
|
||||
-- the point of instantiation the type has a private view,
|
||||
-- install the full view (and that of its ancestors, if any).
|
||||
-- If, in the generic, the aggregate has a global composite type
|
||||
-- and, at the point of instantiation, the type has a private view
|
||||
-- then install the full view.
|
||||
|
||||
declare
|
||||
Assoc : constant Node_Id := Get_Associated_Node (N);
|
||||
|
||||
begin
|
||||
if Present (Assoc)
|
||||
and then Nkind (Assoc) = Nkind (N)
|
||||
and then Present (Etype (Assoc))
|
||||
and then Is_Private_Type (Etype (Assoc))
|
||||
then
|
||||
Switch_View (Etype (Assoc));
|
||||
end if;
|
||||
end;
|
||||
|
||||
-- Moreover, for a full aggregate, if the type is a derived tagged
|
||||
-- type and has a global ancestor, then also restore the full view
|
||||
-- of this ancestor and do so up to the root type. Beware that the
|
||||
-- Ancestor_Type field is overloaded, so test that it's an entity.
|
||||
|
||||
if Nkind (N) = N_Aggregate
|
||||
and then Present (Ancestor_Type (N))
|
||||
and then Nkind (Ancestor_Type (N)) in N_Entity
|
||||
then
|
||||
declare
|
||||
T : Entity_Id := Etype (Get_Associated_Node (N));
|
||||
Rt : Entity_Id;
|
||||
Root_Typ : constant Entity_Id :=
|
||||
Root_Type (Ancestor_Type (N));
|
||||
|
||||
Typ : Entity_Id := Ancestor_Type (N);
|
||||
|
||||
begin
|
||||
if Present (T) and then Is_Private_Type (T) then
|
||||
Switch_View (T);
|
||||
end if;
|
||||
loop
|
||||
if Is_Private_Type (Typ) then
|
||||
Switch_View (Typ);
|
||||
end if;
|
||||
|
||||
if Present (T)
|
||||
and then Is_Tagged_Type (T)
|
||||
and then Is_Derived_Type (T)
|
||||
then
|
||||
Rt := Root_Type (T);
|
||||
exit when Typ = Root_Typ;
|
||||
|
||||
loop
|
||||
T := Etype (T);
|
||||
|
||||
if Is_Private_Type (T) then
|
||||
Switch_View (T);
|
||||
end if;
|
||||
|
||||
exit when T = Rt;
|
||||
end loop;
|
||||
end if;
|
||||
Typ := Etype (Typ);
|
||||
end loop;
|
||||
end;
|
||||
end if;
|
||||
end if;
|
||||
|
|
@ -16431,6 +16519,36 @@ package body Sem_Ch12 is
|
|||
if No (N2) or else No (Typ) or else not Is_Global (Typ) then
|
||||
Set_Associated_Node (N, Empty);
|
||||
|
||||
-- For a full aggregate, if the type is local but is a derived
|
||||
-- tagged type of a global ancestor, we will need to have the
|
||||
-- full view of this global ancestor available in the instance
|
||||
-- in order to analyze the full aggregate.
|
||||
|
||||
if Present (N2)
|
||||
and then Nkind (N2) = N_Aggregate
|
||||
and then Present (Typ)
|
||||
and then Is_Tagged_Type (Typ)
|
||||
and then Is_Derived_Type (Typ)
|
||||
then
|
||||
declare
|
||||
Root_Typ : constant Entity_Id := Root_Type (Typ);
|
||||
|
||||
Parent_Typ : Entity_Id := Typ;
|
||||
|
||||
begin
|
||||
loop
|
||||
Parent_Typ := Etype (Parent_Typ);
|
||||
|
||||
if Is_Global (Parent_Typ) then
|
||||
Set_Ancestor_Type (N, Parent_Typ);
|
||||
exit;
|
||||
end if;
|
||||
|
||||
exit when Parent_Typ = Root_Typ;
|
||||
end loop;
|
||||
end;
|
||||
end if;
|
||||
|
||||
-- If the aggregate is an actual in a call, it has been
|
||||
-- resolved in the current context, to some local type. The
|
||||
-- enclosing call may have been disambiguated by the aggregate,
|
||||
|
|
@ -16469,6 +16587,19 @@ package body Sem_Ch12 is
|
|||
Subtype_Mark => Nam,
|
||||
Expression => Relocate_Node (N));
|
||||
end if;
|
||||
|
||||
-- For a full aggregate, if the type is global and a derived
|
||||
-- tagged type, we will also need to have the full view of its
|
||||
-- ancestor available in the instance in order to analyze the
|
||||
-- full aggregate.
|
||||
|
||||
elsif Present (N2)
|
||||
and then Nkind (N2) = N_Aggregate
|
||||
and then Present (Typ)
|
||||
and then Is_Tagged_Type (Typ)
|
||||
and then Is_Derived_Type (Typ)
|
||||
then
|
||||
Set_Ancestor_Type (N, Etype (Typ));
|
||||
end if;
|
||||
|
||||
if Nkind (N) = N_Aggregate then
|
||||
|
|
|
|||
|
|
@ -5876,39 +5876,116 @@ package body Sem_Ch13 is
|
|||
------------------------------
|
||||
|
||||
procedure Check_Iterator_Functions is
|
||||
function Valid_Default_Iterator (Subp : Entity_Id) return Boolean;
|
||||
-- Check one possible interpretation for validity
|
||||
function Valid_Default_Iterator (Subp : Entity_Id;
|
||||
Ref_Node : Node_Id := Empty)
|
||||
return Boolean;
|
||||
-- Check one possible interpretation for validity. If
|
||||
-- Ref_Node is present report errors on violations.
|
||||
|
||||
----------------------------
|
||||
-- Valid_Default_Iterator --
|
||||
----------------------------
|
||||
|
||||
function Valid_Default_Iterator (Subp : Entity_Id) return Boolean is
|
||||
Root_T : constant Entity_Id := Root_Type (Etype (Etype (Subp)));
|
||||
Formal : Entity_Id;
|
||||
function Valid_Default_Iterator (Subp : Entity_Id;
|
||||
Ref_Node : Node_Id := Empty)
|
||||
return Boolean
|
||||
is
|
||||
Return_Type : constant Entity_Id := Etype (Etype (Subp));
|
||||
Return_Node : Node_Id;
|
||||
Root_T : constant Entity_Id := Root_Type (Return_Type);
|
||||
Formal : Entity_Id;
|
||||
|
||||
function Valid_Iterator_Name (E : Entity_Id) return Boolean
|
||||
is (Chars (E) in Name_Forward_Iterator | Name_Reversible_Iterator);
|
||||
|
||||
function Valid_Iterator_Name (L : Elist_Id) return Boolean;
|
||||
|
||||
-------------------------
|
||||
-- Valid_Iterator_Name --
|
||||
-------------------------
|
||||
|
||||
function Valid_Iterator_Name (L : Elist_Id) return Boolean
|
||||
is
|
||||
Iface_Elmt : Elmt_Id := First_Elmt (L);
|
||||
begin
|
||||
while Present (Iface_Elmt) loop
|
||||
if Valid_Iterator_Name (Node (Iface_Elmt)) then
|
||||
return True;
|
||||
end if;
|
||||
Next_Elmt (Iface_Elmt);
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end Valid_Iterator_Name;
|
||||
|
||||
begin
|
||||
if not Check_Primitive_Function (Subp) then
|
||||
if Subp = Any_Id then
|
||||
if Present (Ref_Node) then
|
||||
|
||||
-- Subp is not resolved and an error will be posted about
|
||||
-- it later
|
||||
|
||||
Error_Msg_N ("improper function for default iterator!",
|
||||
Ref_Node);
|
||||
end if;
|
||||
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if not Check_Primitive_Function (Subp) then
|
||||
if Present (Ref_Node) then
|
||||
Error_Msg_N ("improper function for default iterator!",
|
||||
Ref_Node);
|
||||
Error_Msg_Sloc := Sloc (Subp);
|
||||
Error_Msg_NE
|
||||
("\\default iterator defined # "
|
||||
& "must be a primitive function",
|
||||
Ref_Node, Subp);
|
||||
end if;
|
||||
|
||||
return False;
|
||||
end if;
|
||||
|
||||
-- The return type must be derived from a type in an instance
|
||||
-- of Iterator.Interfaces, and thus its root type must have a
|
||||
-- predefined name.
|
||||
|
||||
elsif Chars (Root_T) /= Name_Forward_Iterator
|
||||
and then Chars (Root_T) /= Name_Reversible_Iterator
|
||||
if not Valid_Iterator_Name (Root_T)
|
||||
and then not (Has_Interfaces (Return_Type) and then
|
||||
Valid_Iterator_Name (Interfaces (Return_Type)))
|
||||
then
|
||||
return False;
|
||||
if Present (Ref_Node) then
|
||||
|
||||
else
|
||||
Formal := First_Formal (Subp);
|
||||
Return_Node := Result_Definition (Parent (Subp));
|
||||
|
||||
Error_Msg_N ("improper function for default iterator!",
|
||||
Ref_Node);
|
||||
Error_Msg_Sloc := Sloc (Return_Node);
|
||||
Error_Msg_NE ("\\return type & # "
|
||||
& "must inherit from either "
|
||||
& "Forward_Iterator or Reversible_Iterator",
|
||||
Ref_Node, Return_Node);
|
||||
end if;
|
||||
|
||||
return False;
|
||||
end if;
|
||||
|
||||
Formal := First_Formal (Subp);
|
||||
|
||||
-- False if any subsequent formal has no default expression
|
||||
|
||||
Next_Formal (Formal);
|
||||
while Present (Formal) loop
|
||||
if No (Expression (Parent (Formal))) then
|
||||
if Present (Ref_Node) then
|
||||
Error_Msg_N ("improper function for default iterator!",
|
||||
Ref_Node);
|
||||
Error_Msg_Sloc := Sloc (Formal);
|
||||
Error_Msg_NE ("\\formal parameter & # "
|
||||
& "must have a default expression",
|
||||
Ref_Node, Formal);
|
||||
end if;
|
||||
|
||||
return False;
|
||||
end if;
|
||||
|
||||
|
|
@ -5920,6 +5997,8 @@ package body Sem_Ch13 is
|
|||
return True;
|
||||
end Valid_Default_Iterator;
|
||||
|
||||
Ignore : Boolean;
|
||||
|
||||
-- Start of processing for Check_Iterator_Functions
|
||||
|
||||
begin
|
||||
|
|
@ -5940,9 +6019,7 @@ package body Sem_Ch13 is
|
|||
|
||||
-- Flag the default_iterator as well as the denoted function.
|
||||
|
||||
if not Valid_Default_Iterator (Entity (Expr)) then
|
||||
Error_Msg_N ("improper function for default iterator!", Expr);
|
||||
end if;
|
||||
Ignore := Valid_Default_Iterator (Entity (Expr), Expr);
|
||||
|
||||
else
|
||||
declare
|
||||
|
|
|
|||
|
|
@ -4957,23 +4957,32 @@ package body Sem_Ch3 is
|
|||
|
||||
if Act_T /= T then
|
||||
declare
|
||||
Full_View_Present : constant Boolean :=
|
||||
Is_Private_Type (Act_T)
|
||||
and then Present (Full_View (Act_T));
|
||||
Full_Act_T : constant Entity_Id :=
|
||||
(if Is_Private_Type (Act_T)
|
||||
then Full_View (Act_T)
|
||||
else Empty);
|
||||
-- Propagate attributes to full view when needed
|
||||
|
||||
begin
|
||||
Set_Is_Constr_Subt_For_U_Nominal (Act_T);
|
||||
|
||||
if Full_View_Present then
|
||||
Set_Is_Constr_Subt_For_U_Nominal (Full_View (Act_T));
|
||||
if Present (Full_Act_T) then
|
||||
Set_Is_Constr_Subt_For_U_Nominal (Full_Act_T);
|
||||
end if;
|
||||
|
||||
if Aliased_Present (N) then
|
||||
Set_Is_Constr_Subt_For_UN_Aliased (Act_T);
|
||||
-- If the object is aliased, then it may be pointed to by an
|
||||
-- access-to-unconstrained-array value, which means that it
|
||||
-- must be allocated with its bounds.
|
||||
|
||||
if Full_View_Present then
|
||||
Set_Is_Constr_Subt_For_UN_Aliased (Full_View (Act_T));
|
||||
if Aliased_Present (N)
|
||||
and then (Is_Array_Type (Act_T)
|
||||
or else (Present (Full_Act_T)
|
||||
and then Is_Array_Type (Full_Act_T)))
|
||||
then
|
||||
Set_Is_Constr_Array_Subt_With_Bounds (Act_T);
|
||||
|
||||
if Present (Full_Act_T) then
|
||||
Set_Is_Constr_Array_Subt_With_Bounds (Full_Act_T);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
|
|
@ -6023,17 +6032,10 @@ package body Sem_Ch3 is
|
|||
-- If this is a subtype declaration for an actual in an instance,
|
||||
-- inherit static and dynamic predicates if any.
|
||||
|
||||
-- If declaration has no aspect specifications, inherit predicate
|
||||
-- info as well. Unclear how to handle the case of both specified
|
||||
-- and inherited predicates ??? Other inherited aspects, such as
|
||||
-- invariants, should be OK, but the combination with later pragmas
|
||||
-- may also require special merging.
|
||||
|
||||
if Has_Predicates (T)
|
||||
and then Present (Predicate_Function (T))
|
||||
and then
|
||||
((In_Instance and then not Comes_From_Source (N))
|
||||
or else No (Aspect_Specifications (N)))
|
||||
and then In_Instance
|
||||
and then not Comes_From_Source (N)
|
||||
then
|
||||
-- Inherit Subprograms_For_Type from the full view, if present
|
||||
|
||||
|
|
|
|||
|
|
@ -6025,17 +6025,17 @@ package body Sem_Ch4 is
|
|||
-- Emit appropriate message. The node will be replaced
|
||||
-- by an appropriate raise statement.
|
||||
|
||||
-- Note that in SPARK mode, as with all calls to apply a
|
||||
-- compile time constraint error, this will be made into
|
||||
-- an error to simplify the processing of the formal
|
||||
-- verification backend.
|
||||
-- Note that in GNATprove mode, as with all calls to
|
||||
-- apply a compile time constraint error, this will be
|
||||
-- made into an error to simplify the processing of the
|
||||
-- formal verification backend.
|
||||
|
||||
Apply_Compile_Time_Constraint_Error
|
||||
(N, "component not present in }??",
|
||||
CE_Discriminant_Check_Failed,
|
||||
Ent => Prefix_Type,
|
||||
Emit_Message =>
|
||||
SPARK_Mode = On or not In_Instance_Not_Visible);
|
||||
GNATprove_Mode or not In_Instance_Not_Visible);
|
||||
return;
|
||||
end if;
|
||||
|
||||
|
|
|
|||
|
|
@ -2691,7 +2691,7 @@ package body Sem_Ch8 is
|
|||
-- Each attempt to find a suitable primitive of a particular
|
||||
-- type operates on its own copy of the original renaming.
|
||||
-- As a result the original renaming is kept decoration and
|
||||
-- side-effect-free.
|
||||
-- side-effect free.
|
||||
|
||||
-- Inherit the overloaded status of the renamed subprogram name
|
||||
|
||||
|
|
@ -6550,6 +6550,16 @@ package body Sem_Ch8 is
|
|||
|
||||
Decl := Enclosing_Declaration (E);
|
||||
|
||||
-- Enclosing_Declaration does not always return a
|
||||
-- declaration; cope with this irregularity.
|
||||
if Decl in N_Subprogram_Specification_Id
|
||||
and then Nkind (Parent (Decl)) in
|
||||
N_Subprogram_Body | N_Subprogram_Declaration
|
||||
| N_Subprogram_Renaming_Declaration
|
||||
then
|
||||
Decl := Parent (Decl);
|
||||
end if;
|
||||
|
||||
-- Look for the suprogram renaming declaration built
|
||||
-- for a generic actual subprogram. Unclear why
|
||||
-- Original_Node call is needed, but sometimes it is.
|
||||
|
|
|
|||
|
|
@ -283,8 +283,7 @@ package body Sem_Prag is
|
|||
function Is_Unconstrained_Or_Tagged_Item (Item : Entity_Id) return Boolean;
|
||||
-- Subsidiary to Collect_Subprogram_Inputs_Outputs and the analysis of
|
||||
-- pragma Depends. Determine whether the type of dependency item Item is
|
||||
-- tagged, unconstrained array, unconstrained record or a record with at
|
||||
-- least one unconstrained component.
|
||||
-- tagged, unconstrained array or unconstrained record.
|
||||
|
||||
procedure Record_Possible_Body_Reference
|
||||
(State_Id : Entity_Id;
|
||||
|
|
@ -23375,15 +23374,13 @@ package body Sem_Prag is
|
|||
Analyze_If_Present (Pragma_SPARK_Mode);
|
||||
|
||||
-- State refinement is allowed only when the corresponding package
|
||||
-- declaration has non-null pragma Abstract_State. Refinement not
|
||||
-- enforced when SPARK checks are suppressed (SPARK RM 7.2.2(3)).
|
||||
-- declaration has non-null pragma Abstract_State (SPARK RM
|
||||
-- 7.2.2(3)).
|
||||
|
||||
if SPARK_Mode /= Off
|
||||
and then
|
||||
(No (Abstract_States (Spec_Id))
|
||||
or else Has_Null_Abstract_State (Spec_Id))
|
||||
if No (Abstract_States (Spec_Id))
|
||||
or else Has_Null_Abstract_State (Spec_Id)
|
||||
then
|
||||
Error_Msg_NE
|
||||
SPARK_Msg_NE
|
||||
("useless refinement, package & does not define abstract "
|
||||
& "states", N, Spec_Id);
|
||||
return;
|
||||
|
|
@ -32959,36 +32956,7 @@ package body Sem_Prag is
|
|||
function Is_Unconstrained_Or_Tagged_Item
|
||||
(Item : Entity_Id) return Boolean
|
||||
is
|
||||
function Has_Unconstrained_Component (Typ : Entity_Id) return Boolean;
|
||||
-- Determine whether record type Typ has at least one unconstrained
|
||||
-- component.
|
||||
|
||||
---------------------------------
|
||||
-- Has_Unconstrained_Component --
|
||||
---------------------------------
|
||||
|
||||
function Has_Unconstrained_Component (Typ : Entity_Id) return Boolean is
|
||||
Comp : Entity_Id;
|
||||
|
||||
begin
|
||||
Comp := First_Component (Typ);
|
||||
while Present (Comp) loop
|
||||
if Is_Unconstrained_Or_Tagged_Item (Comp) then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
Next_Component (Comp);
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end Has_Unconstrained_Component;
|
||||
|
||||
-- Local variables
|
||||
|
||||
Typ : constant Entity_Id := Etype (Item);
|
||||
|
||||
-- Start of processing for Is_Unconstrained_Or_Tagged_Item
|
||||
|
||||
begin
|
||||
if Is_Tagged_Type (Typ) then
|
||||
return True;
|
||||
|
|
@ -32997,11 +32965,7 @@ package body Sem_Prag is
|
|||
return True;
|
||||
|
||||
elsif Is_Record_Type (Typ) then
|
||||
if Has_Discriminants (Typ) and then not Is_Constrained (Typ) then
|
||||
return True;
|
||||
else
|
||||
return Has_Unconstrained_Component (Typ);
|
||||
end if;
|
||||
return Has_Discriminants (Typ) and then not Is_Constrained (Typ);
|
||||
|
||||
elsif Is_Private_Type (Typ) and then Has_Discriminants (Typ) then
|
||||
return True;
|
||||
|
|
|
|||
|
|
@ -7787,14 +7787,6 @@ package body Sem_Res is
|
|||
-- Determine whether Expr is part of an N_Attribute_Reference
|
||||
-- expression.
|
||||
|
||||
function In_Attribute_Old (Expr : Node_Id) return Boolean;
|
||||
-- Determine whether Expr is in attribute Old
|
||||
|
||||
function Within_Exceptional_Cases_Consequence
|
||||
(Expr : Node_Id)
|
||||
return Boolean;
|
||||
-- Determine whether Expr is part of an Exceptional_Cases consequence
|
||||
|
||||
----------------------------------------
|
||||
-- Is_Assignment_Or_Object_Expression --
|
||||
----------------------------------------
|
||||
|
|
@ -7836,31 +7828,6 @@ package body Sem_Res is
|
|||
end if;
|
||||
end Is_Assignment_Or_Object_Expression;
|
||||
|
||||
----------------------
|
||||
-- In_Attribute_Old --
|
||||
----------------------
|
||||
|
||||
function In_Attribute_Old (Expr : Node_Id) return Boolean is
|
||||
N : Node_Id := Expr;
|
||||
begin
|
||||
while Present (N) loop
|
||||
if Nkind (N) = N_Attribute_Reference
|
||||
and then Attribute_Name (N) = Name_Old
|
||||
then
|
||||
return True;
|
||||
|
||||
-- Prevent the search from going too far
|
||||
|
||||
elsif Is_Body_Or_Package_Declaration (N) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
N := Parent (N);
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end In_Attribute_Old;
|
||||
|
||||
-----------------------------
|
||||
-- Is_Attribute_Expression --
|
||||
-----------------------------
|
||||
|
|
@ -7884,39 +7851,6 @@ package body Sem_Res is
|
|||
return False;
|
||||
end Is_Attribute_Expression;
|
||||
|
||||
------------------------------------------
|
||||
-- Within_Exceptional_Cases_Consequence --
|
||||
------------------------------------------
|
||||
|
||||
function Within_Exceptional_Cases_Consequence
|
||||
(Expr : Node_Id)
|
||||
return Boolean
|
||||
is
|
||||
Context : Node_Id := Parent (Expr);
|
||||
begin
|
||||
while Present (Context) loop
|
||||
if Nkind (Context) = N_Pragma then
|
||||
|
||||
-- In Exceptional_Cases references to formal parameters are
|
||||
-- only allowed within consequences, so it is enough to
|
||||
-- recognize the pragma itself.
|
||||
|
||||
if Get_Pragma_Id (Context) = Pragma_Exceptional_Cases then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
-- Prevent the search from going too far
|
||||
|
||||
elsif Is_Body_Or_Package_Declaration (Context) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
Context := Parent (Context);
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end Within_Exceptional_Cases_Consequence;
|
||||
|
||||
-- Local variables
|
||||
|
||||
E : constant Entity_Id := Entity (N);
|
||||
|
|
@ -8048,40 +7982,6 @@ package body Sem_Res is
|
|||
|
||||
if SPARK_Mode = On then
|
||||
|
||||
-- Parameters of modes OUT or IN OUT of the subprogram shall not
|
||||
-- occur in the consequences of an exceptional contract unless
|
||||
-- they are either passed by reference or occur in the prefix
|
||||
-- of a reference to the 'Old attribute. For convenience, we also
|
||||
-- allow them as prefixes of attributes that do not actually read
|
||||
-- data from the object.
|
||||
|
||||
if Ekind (E) in E_Out_Parameter | E_In_Out_Parameter
|
||||
and then Scope (E) = Current_Scope_No_Loops
|
||||
and then Within_Exceptional_Cases_Consequence (N)
|
||||
and then not In_Attribute_Old (N)
|
||||
and then not (Nkind (Parent (N)) = N_Attribute_Reference
|
||||
and then
|
||||
Attribute_Name (Parent (N)) in Name_Constrained
|
||||
| Name_First
|
||||
| Name_Last
|
||||
| Name_Length
|
||||
| Name_Range)
|
||||
and then not Is_By_Reference_Type (Etype (E))
|
||||
and then not Is_Aliased (E)
|
||||
then
|
||||
if Ekind (E) = E_Out_Parameter then
|
||||
Error_Msg_N
|
||||
("formal parameter of mode `OUT` cannot appear " &
|
||||
"in consequence of Exceptional_Cases", N);
|
||||
else
|
||||
Error_Msg_N
|
||||
("formal parameter of mode `IN OUT` cannot appear " &
|
||||
"in consequence of Exceptional_Cases", N);
|
||||
end if;
|
||||
Error_Msg_N
|
||||
("\only parameters passed by reference are allowed", N);
|
||||
end if;
|
||||
|
||||
-- Check for possible elaboration issues with respect to reads of
|
||||
-- variables. The act of renaming the variable is not considered a
|
||||
-- read as it simply establishes an alias.
|
||||
|
|
|
|||
|
|
@ -1813,51 +1813,6 @@ package body Sem_Util is
|
|||
------------------------------
|
||||
|
||||
function Build_Default_Subtype_OK (T : Entity_Id) return Boolean is
|
||||
|
||||
function Default_Discriminant_Values_Known_At_Compile_Time
|
||||
(T : Entity_Id) return Boolean;
|
||||
-- For an unconstrained type T, return False if the given type has a
|
||||
-- discriminant with default value not known at compile time. Return
|
||||
-- True otherwise.
|
||||
|
||||
---------------------------------------------------------
|
||||
-- Default_Discriminant_Values_Known_At_Compile_Time --
|
||||
---------------------------------------------------------
|
||||
|
||||
function Default_Discriminant_Values_Known_At_Compile_Time
|
||||
(T : Entity_Id) return Boolean
|
||||
is
|
||||
Discr : Entity_Id;
|
||||
DDV : Node_Id;
|
||||
|
||||
begin
|
||||
|
||||
-- If the type has no discriminant, we know them all at compile time
|
||||
|
||||
if not Has_Discriminants (T) then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
-- The type has discriminants, check that none of them has a default
|
||||
-- value not known at compile time.
|
||||
|
||||
Discr := First_Discriminant (T);
|
||||
|
||||
while Present (Discr) loop
|
||||
DDV := Discriminant_Default_Value (Discr);
|
||||
|
||||
if Present (DDV) and then not Compile_Time_Known_Value (DDV) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
Next_Discriminant (Discr);
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Default_Discriminant_Values_Known_At_Compile_Time;
|
||||
|
||||
-- Start of processing for Build_Default_Subtype_OK
|
||||
|
||||
begin
|
||||
|
||||
if Is_Constrained (T) then
|
||||
|
|
@ -1867,18 +1822,6 @@ package body Sem_Util is
|
|||
return False;
|
||||
end if;
|
||||
|
||||
if not Default_Discriminant_Values_Known_At_Compile_Time (T) then
|
||||
|
||||
-- This is a special case of definite subtypes. To allocate a
|
||||
-- specific size to the subtype, we need to know the value at compile
|
||||
-- time. This might not be the case if the default value is the
|
||||
-- result of a function. In that case, the object might be definite
|
||||
-- and limited but the needed size might not be statically known or
|
||||
-- too tricky to obtain. In that case, we will not build the subtype.
|
||||
|
||||
return False;
|
||||
end if;
|
||||
|
||||
return Is_Definite_Subtype (T) and then Is_Inherently_Limited_Type (T);
|
||||
end Build_Default_Subtype_OK;
|
||||
|
||||
|
|
@ -12406,14 +12349,15 @@ package body Sem_Util is
|
|||
|
||||
function Is_Container_Aggregate (Exp : Node_Id) return Boolean is
|
||||
|
||||
function Is_Record_Aggregate return Boolean is (False);
|
||||
-- ??? Unimplemented. Given an aggregate whose type is a
|
||||
-- record type with specified Aggregate aspect, how do we
|
||||
-- determine whether it is a record aggregate or a container
|
||||
-- aggregate? If the code where the aggregate occurs can see only
|
||||
-- a partial view of the aggregate's type then the aggregate
|
||||
-- cannot be a record type; an aggregate of a private type has to
|
||||
-- be a container aggregate.
|
||||
function Is_Record_Aggregate return Boolean is
|
||||
(Is_Parenthesis_Aggregate (Exp));
|
||||
-- Given an aggregate whose type is a record type with specified
|
||||
-- Aggregate aspect, we determine whether it is a record aggregate or
|
||||
-- a container aggregate by ckecking whether it uses parentheses () or
|
||||
-- square brackets []. If the code where the aggregate occurs can see
|
||||
-- only a partial view of the aggregate's type then the aggregate cannot
|
||||
-- be a record type and must then use []; an aggregate of a private type
|
||||
-- has to be a container aggregate and must then use [].
|
||||
|
||||
begin
|
||||
return Nkind (Exp) = N_Aggregate
|
||||
|
|
@ -14587,11 +14531,16 @@ package body Sem_Util is
|
|||
-- A named subtype does not inherit the predicate function of its
|
||||
-- parent but an itype declared for a loop index needs the discrete
|
||||
-- predicate information of its parent to execute the loop properly.
|
||||
-- Moreover, a named private subtype whose full view is an itype also
|
||||
-- needs to inherit a predicate function because it will not be frozen.
|
||||
-- A non-discrete type may has a static predicate (for example True)
|
||||
-- but has no static_discrete_predicate.
|
||||
|
||||
if not Only_Flags
|
||||
and then Is_Itype (Subt)
|
||||
and then (Is_Itype (Subt)
|
||||
or else (Ekind (Subt) = E_Private_Subtype
|
||||
and then Present (Full_View (Subt))
|
||||
and then Is_Itype (Full_View (Subt))))
|
||||
and then Present (Predicate_Function (Par))
|
||||
then
|
||||
Set_Subprograms_For_Type (Subt, Subprograms_For_Type (Par));
|
||||
|
|
@ -16036,7 +15985,7 @@ package body Sem_Util is
|
|||
Param_Typ := Etype (Param);
|
||||
end if;
|
||||
|
||||
-- In the case where an Itype was created for a dispatchin call, the
|
||||
-- In the case where an Itype was created for a dispatching call, the
|
||||
-- procedure call has been rewritten. The actual may be an access to
|
||||
-- interface type in which case it is the designated type that is the
|
||||
-- controlling type.
|
||||
|
|
|
|||
|
|
@ -282,14 +282,13 @@ package Sem_Util is
|
|||
-- subtype. Otherwise, simply return T.
|
||||
|
||||
function Build_Default_Subtype_OK (T : Entity_Id) return Boolean;
|
||||
-- When analyzing components or object declarations, it is possible, in
|
||||
-- some cases, to build subtypes for discriminated types. This is
|
||||
-- worthwhile to avoid the backend allocating the maximum possible size for
|
||||
-- objects of the type.
|
||||
-- When analyzing object declarations, it is possible, in some cases, to
|
||||
-- build subtypes for discriminated types. This is worthwhile to avoid the
|
||||
-- backend allocating the maximum possible size for objects of the type.
|
||||
-- In particular, when T is limited, the discriminants and therefore the
|
||||
-- size of an object of type T cannot change. Furthermore, if T is definite
|
||||
-- with statically initialized defaulted discriminants, we are able and
|
||||
-- want to build a constrained subtype of the right size.
|
||||
-- with initialized defaulted discriminants, we are able and want to build
|
||||
-- a constrained subtype of the right size.
|
||||
|
||||
function Build_Discriminal_Subtype_Of_Component
|
||||
(T : Entity_Id) return Node_Id;
|
||||
|
|
|
|||
|
|
@ -157,6 +157,22 @@ package Sinfo.Utils is
|
|||
(N : N_Inclusive_Has_Entity; Val : Node_Id)
|
||||
renames Set_Entity_Or_Associated_Node;
|
||||
|
||||
---------------------------------------------------
|
||||
-- Aliases for Aggregate_Bounds_Or_Ancestor_Type --
|
||||
---------------------------------------------------
|
||||
|
||||
function Aggregate_Bounds (N : Node_Id) return Node_Id
|
||||
renames Aggregate_Bounds_Or_Ancestor_Type;
|
||||
|
||||
function Ancestor_Type (N : Node_Id) return Node_Id
|
||||
renames Aggregate_Bounds_Or_Ancestor_Type;
|
||||
|
||||
procedure Set_Aggregate_Bounds (N : Node_Id; Val : Node_Id)
|
||||
renames Set_Aggregate_Bounds_Or_Ancestor_Type;
|
||||
|
||||
procedure Set_Ancestor_Type (N : Node_Id; Val : Node_Id)
|
||||
renames Set_Aggregate_Bounds_Or_Ancestor_Type;
|
||||
|
||||
---------------
|
||||
-- Debugging --
|
||||
---------------
|
||||
|
|
|
|||
|
|
@ -845,6 +845,11 @@ package Sinfo is
|
|||
-- is used for translation of the at end handler into a normal exception
|
||||
-- handler.
|
||||
|
||||
-- Ancestor_Type
|
||||
-- Present in record N_Aggregate nodes. Used to store the first global
|
||||
-- ancestor of the type of the aggregate in a generic context, if any,
|
||||
-- when the type is a derived tagged type. Otherwise Empty.
|
||||
|
||||
-- Aspect_On_Partial_View
|
||||
-- Present on an N_Aspect_Specification node. For an aspect that applies
|
||||
-- to a type entity, indicates whether the specification appears on the
|
||||
|
|
@ -4081,7 +4086,7 @@ package Sinfo is
|
|||
-- Expressions (set to No_List if none or null record case)
|
||||
-- Component_Associations (set to No_List if none)
|
||||
-- Null_Record_Present
|
||||
-- Aggregate_Bounds
|
||||
-- Aggregate_Bounds (array) or Ancestor_Type (record)
|
||||
-- Associated_Node
|
||||
-- Compile_Time_Known_Aggregate
|
||||
-- Expansion_Delayed
|
||||
|
|
|
|||
|
|
@ -460,19 +460,6 @@ package body Sinput is
|
|||
end if;
|
||||
end Get_Logical_Line_Number;
|
||||
|
||||
---------------------------------
|
||||
-- Get_Logical_Line_Number_Img --
|
||||
---------------------------------
|
||||
|
||||
function Get_Logical_Line_Number_Img
|
||||
(P : Source_Ptr) return String
|
||||
is
|
||||
begin
|
||||
Name_Len := 0;
|
||||
Add_Nat_To_Name_Buffer (Nat (Get_Logical_Line_Number (P)));
|
||||
return Name_Buffer (1 .. Name_Len);
|
||||
end Get_Logical_Line_Number_Img;
|
||||
|
||||
------------------------------
|
||||
-- Get_Physical_Line_Number --
|
||||
------------------------------
|
||||
|
|
|
|||
|
|
@ -541,11 +541,6 @@ package Sinput is
|
|||
|
||||
-- WARNING: There is a matching C declaration of this subprogram in fe.h
|
||||
|
||||
function Get_Logical_Line_Number_Img
|
||||
(P : Source_Ptr) return String;
|
||||
-- Same as above function, but returns the line number as a string of
|
||||
-- decimal digits, with no leading space. Destroys Name_Buffer.
|
||||
|
||||
function Get_Physical_Line_Number
|
||||
(P : Source_Ptr) return Physical_Line_Number;
|
||||
-- The line number of the specified source position is obtained by
|
||||
|
|
|
|||
|
|
@ -272,16 +272,8 @@ package Targparm is
|
|||
-- If Command_Line_Args_On_Target is set to False, then the
|
||||
-- generation of these variables is suppressed completely.
|
||||
--
|
||||
-- The binder generates the gnat_exit_status variable in the binder
|
||||
-- file instead of being imported from the run-time library. If
|
||||
-- Exit_Status_Supported_On_Target is set to False, then the
|
||||
-- generation of this variable is suppressed entirely.
|
||||
--
|
||||
-- The routine __gnat_break_start is defined within the binder file
|
||||
-- instead of being imported from the run-time library.
|
||||
--
|
||||
-- The variable __gnat_exit_status is generated within the binder file
|
||||
-- instead of being imported from the run-time library.
|
||||
|
||||
Suppress_Standard_Library_On_Target : Boolean := False;
|
||||
-- If this flag is True, then the standard library is not included by
|
||||
|
|
@ -461,19 +453,17 @@ package Targparm is
|
|||
-- required on such targets (RM A.15(13)).
|
||||
|
||||
Command_Line_Args_On_Target : Boolean := True;
|
||||
-- Set False if no command line arguments on target. Note that if this
|
||||
-- is False in with Configurable_Run_Time_On_Target set to True, then
|
||||
-- this causes suppression of generation of the argv/argc variables
|
||||
-- used to record command line arguments.
|
||||
-- Set False if no command line arguments on target. This will suppress
|
||||
-- generation of references to the argv/argc variables used to record
|
||||
-- command line arguments.
|
||||
|
||||
-- Similarly, most targets support the use of an exit status, but other
|
||||
-- targets might not, as allowed by RM A.15(18-20).
|
||||
|
||||
Exit_Status_Supported_On_Target : Boolean := True;
|
||||
-- Set False if returning of an exit status is not supported on target.
|
||||
-- Note that if this False in with Configurable_Run_Time_On_Target
|
||||
-- set to True, then this causes suppression of the gnat_exit_status
|
||||
-- variable used to record the exit status.
|
||||
-- This will cause the binder to not generate a reference to the
|
||||
-- gnat_exit_status run-time symbol.
|
||||
|
||||
-----------------------
|
||||
-- Main Program Name --
|
||||
|
|
|
|||
|
|
@ -328,8 +328,6 @@ package body Treepr is
|
|||
return "Has_RACW";
|
||||
when F_Ignore_SPARK_Mode_Pragmas =>
|
||||
return "Ignore_SPARK_Mode_Pragmas";
|
||||
when F_Is_Constr_Subt_For_UN_Aliased =>
|
||||
return "Is_Constr_Subt_For_UN_Aliased";
|
||||
when F_Is_CPP_Class =>
|
||||
return "Is_CPP_Class";
|
||||
when F_Is_CUDA_Kernel =>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,132 @@
|
|||
2023-12-16 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* analyzer.cc: Include "tree-pretty-print.h" and
|
||||
"diagnostic-event-id.h".
|
||||
(tree_to_json): New.
|
||||
(diagnostic_event_id_to_json): New.
|
||||
(bit_offset_to_json): New.
|
||||
(byte_offset_to_json): New.
|
||||
* analyzer.h (tree_to_json): New decl.
|
||||
(diagnostic_event_id_to_json): New decl.
|
||||
(bit_offset_to_json): New decl.
|
||||
(byte_offset_to_json): New decl.
|
||||
* bounds-checking.cc: Include "diagnostic-format-sarif.h".
|
||||
(out_of_bounds::maybe_add_sarif_properties): New.
|
||||
(concrete_out_of_bounds::maybe_add_sarif_properties): New.
|
||||
(concrete_past_the_end::maybe_add_sarif_properties): New.
|
||||
(symbolic_past_the_end::maybe_add_sarif_properties): New.
|
||||
* region-model.cc (region_to_value_map::to_json): New.
|
||||
(region_model::to_json): New.
|
||||
* region-model.h (region_to_value_map::to_json): New decl.
|
||||
(region_model::to_json): New decl.
|
||||
* store.cc (bit_range::to_json): New.
|
||||
(byte_range::to_json): New.
|
||||
* store.h (bit_range::to_json): New decl.
|
||||
(byte_range::to_json): New decl.
|
||||
|
||||
2023-12-16 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/112792
|
||||
* bounds-checking.cc
|
||||
(out_of_bounds::oob_region_creation_event_capacity): Rename
|
||||
"capacity" to "byte_capacity". Layout fix.
|
||||
(out_of_bounds::::add_region_creation_events): Rename
|
||||
"capacity" to "byte_capacity".
|
||||
(class concrete_out_of_bounds): Rename m_out_of_bounds_range to
|
||||
m_out_of_bounds_bits and convert from a byte_range to a bit_range.
|
||||
(concrete_out_of_bounds::get_out_of_bounds_bytes): New.
|
||||
(concrete_past_the_end::concrete_past_the_end): Rename param
|
||||
"byte_bound" to "bit_bound". Initialize m_byte_bound.
|
||||
(concrete_past_the_end::subclass_equal_p): Update for renaming
|
||||
of m_byte_bound to m_bit_bound.
|
||||
(concrete_past_the_end::m_bit_bound): New field.
|
||||
(concrete_buffer_overflow::concrete_buffer_overflow): Convert
|
||||
param "range" from byte_range to bit_range. Rename param
|
||||
"byte_bound" to "bit_bound".
|
||||
(concrete_buffer_overflow::emit): Update for bits vs bytes.
|
||||
(concrete_buffer_overflow::describe_final_event): Split
|
||||
into...
|
||||
(concrete_buffer_overflow::describe_final_event_as_bytes): ...this
|
||||
(concrete_buffer_overflow::describe_final_event_as_bits): ...and
|
||||
this.
|
||||
(concrete_buffer_over_read::concrete_buffer_over_read): Convert
|
||||
param "range" from byte_range to bit_range. Rename param
|
||||
"byte_bound" to "bit_bound".
|
||||
(concrete_buffer_over_read::emit): Update for bits vs bytes.
|
||||
(concrete_buffer_over_read::describe_final_event): Split into...
|
||||
(concrete_buffer_over_read::describe_final_event_as_bytes):
|
||||
...this
|
||||
(concrete_buffer_over_read::describe_final_event_as_bits): ...and
|
||||
this.
|
||||
(concrete_buffer_underwrite::concrete_buffer_underwrite): Convert
|
||||
param "range" from byte_range to bit_range.
|
||||
(concrete_buffer_underwrite::describe_final_event): Split into...
|
||||
(concrete_buffer_underwrite::describe_final_event_as_bytes):
|
||||
...this
|
||||
(concrete_buffer_underwrite::describe_final_event_as_bits): ...and
|
||||
this.
|
||||
(concrete_buffer_under_read::concrete_buffer_under_read): Convert
|
||||
param "range" from byte_range to bit_range.
|
||||
(concrete_buffer_under_read::describe_final_event): Split into...
|
||||
(concrete_buffer_under_read::describe_final_event_as_bytes):
|
||||
...this
|
||||
(concrete_buffer_under_read::describe_final_event_as_bits): ...and
|
||||
this.
|
||||
(region_model::check_region_bounds): Use bits for concrete values,
|
||||
and rename locals to indicate whether we're dealing with bits or
|
||||
bytes. Specifically, replace "num_bytes_sval" with
|
||||
"num_bits_sval", and get it from reg's "get_bit_size_sval".
|
||||
Replace "num_bytes_tree" with "num_bits_tree". Rename "capacity"
|
||||
to "byte_capacity". Rename "cst_capacity_tree" to
|
||||
"cst_byte_capacity_tree". Replace "offset" and
|
||||
"num_bytes_unsigned" with "bit_offset" and "num_bits_unsigned"
|
||||
respectively, converting from byte_offset_t to bit_offset_t.
|
||||
Replace "out" and "read_bytes" with "bits_outside" and "read_bits"
|
||||
respectively, converting from byte_range to bit_range. Convert
|
||||
"buffer" from byte_range to bit_range. Replace "byte_bound" with
|
||||
"bit_bound".
|
||||
* region.cc (region::get_bit_size_sval): New.
|
||||
(offset_region::get_bit_offset): New.
|
||||
(offset_region::get_bit_size_sval): New.
|
||||
(sized_region::get_bit_size_sval): New.
|
||||
(bit_range_region::get_bit_size_sval): New.
|
||||
* region.h (region::get_bit_size_sval): New vfunc.
|
||||
(offset_region::get_bit_offset): New decl.
|
||||
(offset_region::get_bit_size_sval): New decl.
|
||||
(sized_region::get_bit_size_sval): New decl.
|
||||
(bit_range_region::get_bit_size_sval): New decl.
|
||||
* store.cc (bit_range::intersects_p): New, based on
|
||||
byte_range::intersects_p.
|
||||
(bit_range::exceeds_p): New, based on byte_range::exceeds_p.
|
||||
(bit_range::falls_short_of_p): New, based on
|
||||
byte_range::falls_short_of_p.
|
||||
(byte_range::intersects_p): Delete.
|
||||
(byte_range::exceeds_p): Delete.
|
||||
(byte_range::falls_short_of_p): Delete.
|
||||
* store.h (bit_range::intersects_p): New overload.
|
||||
(bit_range::exceeds_p): New.
|
||||
(bit_range::falls_short_of_p): New.
|
||||
(byte_range::intersects_p): Delete.
|
||||
(byte_range::exceeds_p): Delete.
|
||||
(byte_range::falls_short_of_p): Delete.
|
||||
|
||||
2023-12-14 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/112655
|
||||
* infinite-loop.cc (infinite_loop::infinite_loop): Pass eedges
|
||||
via rvalue reference rather than by value.
|
||||
(starts_infinite_loop_p): Move eedges when constructing an
|
||||
infinite_loop instance.
|
||||
* sm-file.cc (fileptr_state_machine::fileptr_state_machine): Use
|
||||
initializer list for states.
|
||||
* sm-sensitive.cc
|
||||
(sensitive_state_machine::sensitive_state_machine): Likewise.
|
||||
* sm-signal.cc (signal_state_machine::signal_state_machine):
|
||||
Likewise.
|
||||
* sm-taint.cc (taint_state_machine::taint_state_machine):
|
||||
Likewise.
|
||||
* varargs.cc (va_list_state_machine::va_list_state_machine): Likewise.
|
||||
|
||||
2023-12-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/112955
|
||||
|
|
@ -11389,7 +11518,7 @@
|
|||
* Initial creation
|
||||
|
||||
|
||||
Copyright (C) 2019-2023 Free Software Foundation, Inc.
|
||||
Copyright (C) 2019-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "diagnostic.h"
|
||||
#include "intl.h"
|
||||
#include "analyzer/analyzer.h"
|
||||
#include "tree-pretty-print.h"
|
||||
#include "diagnostic-event-id.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
|
@ -216,6 +218,63 @@ get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
|
|||
return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
|
||||
}
|
||||
|
||||
/* Generate a JSON value for NODE, which can be NULL_TREE.
|
||||
This is intended for debugging the analyzer rather than serialization and
|
||||
thus is a string (or null, for NULL_TREE). */
|
||||
|
||||
json::value *
|
||||
tree_to_json (tree node)
|
||||
{
|
||||
if (!node)
|
||||
return new json::literal (json::JSON_NULL);
|
||||
|
||||
pretty_printer pp;
|
||||
dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
|
||||
return new json::string (pp_formatted_text (&pp));
|
||||
}
|
||||
|
||||
/* Generate a JSON value for EVENT_ID.
|
||||
This is intended for debugging the analyzer rather than serialization and
|
||||
thus is a string matching those seen in event messags (or null,
|
||||
for unknown). */
|
||||
|
||||
json::value *
|
||||
diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
|
||||
{
|
||||
if (event_id.known_p ())
|
||||
{
|
||||
pretty_printer pp;
|
||||
pp_printf (&pp, "%@", &event_id);
|
||||
return new json::string (pp_formatted_text (&pp));
|
||||
}
|
||||
else
|
||||
return new json::literal (json::JSON_NULL);
|
||||
}
|
||||
|
||||
/* Generate a JSON value for OFFSET.
|
||||
This is intended for debugging the analyzer rather than serialization and
|
||||
thus is a string. */
|
||||
|
||||
json::value *
|
||||
bit_offset_to_json (const bit_offset_t &offset)
|
||||
{
|
||||
pretty_printer pp;
|
||||
pp_wide_int_large (&pp, offset, SIGNED);
|
||||
return new json::string (pp_formatted_text (&pp));
|
||||
}
|
||||
|
||||
/* Generate a JSON value for OFFSET.
|
||||
This is intended for debugging the analyzer rather than serialization and
|
||||
thus is a string. */
|
||||
|
||||
json::value *
|
||||
byte_offset_to_json (const byte_offset_t &offset)
|
||||
{
|
||||
pretty_printer pp;
|
||||
pp_wide_int_large (&pp, offset, SIGNED);
|
||||
return new json::string (pp_formatted_text (&pp));
|
||||
}
|
||||
|
||||
} // namespace ana
|
||||
|
||||
/* Helper function for checkers. Is the CALL to the given function name,
|
||||
|
|
|
|||
|
|
@ -415,6 +415,18 @@ extern void log_stashed_constants (logger *logger);
|
|||
|
||||
extern FILE *get_or_create_any_logfile ();
|
||||
|
||||
extern json::value *
|
||||
tree_to_json (tree node);
|
||||
|
||||
extern json::value *
|
||||
diagnostic_event_id_to_json (const diagnostic_event_id_t &);
|
||||
|
||||
extern json::value *
|
||||
bit_offset_to_json (const bit_offset_t &offset);
|
||||
|
||||
extern json::value *
|
||||
byte_offset_to_json (const byte_offset_t &offset);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
extern bool is_special_named_call_p (const gcall *call, const char *funcname,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "gimple-iterator.h"
|
||||
#include "diagnostic-core.h"
|
||||
#include "diagnostic-diagram.h"
|
||||
#include "diagnostic-format-sarif.h"
|
||||
#include "analyzer/analyzer.h"
|
||||
#include "analyzer/analyzer-logging.h"
|
||||
#include "analyzer/region-model.h"
|
||||
|
|
@ -50,12 +51,12 @@ public:
|
|||
class oob_region_creation_event_capacity : public region_creation_event_capacity
|
||||
{
|
||||
public:
|
||||
oob_region_creation_event_capacity (tree capacity,
|
||||
oob_region_creation_event_capacity (tree byte_capacity,
|
||||
const event_loc_info &loc_info,
|
||||
out_of_bounds &oob)
|
||||
: region_creation_event_capacity (capacity,
|
||||
loc_info),
|
||||
m_oob (oob)
|
||||
: region_creation_event_capacity (byte_capacity,
|
||||
loc_info),
|
||||
m_oob (oob)
|
||||
{
|
||||
}
|
||||
void prepare_for_emission (checker_path *path,
|
||||
|
|
@ -67,7 +68,7 @@ public:
|
|||
emission_id);
|
||||
m_oob.m_region_creation_event_id = emission_id;
|
||||
}
|
||||
private:
|
||||
private:
|
||||
out_of_bounds &m_oob;
|
||||
};
|
||||
|
||||
|
|
@ -97,18 +98,36 @@ public:
|
|||
}
|
||||
|
||||
void add_region_creation_events (const region *,
|
||||
tree capacity,
|
||||
tree byte_capacity,
|
||||
const event_loc_info &loc_info,
|
||||
checker_path &emission_path) override
|
||||
{
|
||||
/* The memory space is described in the diagnostic message itself,
|
||||
so we don't need an event for that. */
|
||||
if (capacity)
|
||||
if (byte_capacity)
|
||||
emission_path.add_event
|
||||
(make_unique<oob_region_creation_event_capacity> (capacity, loc_info,
|
||||
(make_unique<oob_region_creation_event_capacity> (byte_capacity,
|
||||
loc_info,
|
||||
*this));
|
||||
}
|
||||
|
||||
void maybe_add_sarif_properties (sarif_object &result_obj)
|
||||
const override
|
||||
{
|
||||
sarif_property_bag &props = result_obj.get_or_create_properties ();
|
||||
#define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/"
|
||||
props.set_string (PROPERTY_PREFIX "dir",
|
||||
get_dir () == DIR_READ ? "read" : "write");
|
||||
props.set (PROPERTY_PREFIX "model", m_model.to_json ());
|
||||
props.set (PROPERTY_PREFIX "region", m_reg->to_json ());
|
||||
props.set (PROPERTY_PREFIX "diag_arg", tree_to_json (m_diag_arg));
|
||||
if (m_sval_hint)
|
||||
props.set (PROPERTY_PREFIX "sval_hint", m_sval_hint->to_json ());
|
||||
props.set (PROPERTY_PREFIX "region_creation_event_id",
|
||||
diagnostic_event_id_to_json (m_region_creation_event_id));
|
||||
#undef PROPERTY_PREFIX
|
||||
}
|
||||
|
||||
virtual enum access_direction get_dir () const = 0;
|
||||
|
||||
protected:
|
||||
|
|
@ -205,10 +224,10 @@ class concrete_out_of_bounds : public out_of_bounds
|
|||
public:
|
||||
concrete_out_of_bounds (const region_model &model,
|
||||
const region *reg, tree diag_arg,
|
||||
byte_range out_of_bounds_range,
|
||||
bit_range out_of_bounds_bits,
|
||||
const svalue *sval_hint)
|
||||
: out_of_bounds (model, reg, diag_arg, sval_hint),
|
||||
m_out_of_bounds_range (out_of_bounds_range)
|
||||
m_out_of_bounds_bits (out_of_bounds_bits)
|
||||
{}
|
||||
|
||||
bool subclass_equal_p (const pending_diagnostic &base_other) const override
|
||||
|
|
@ -216,11 +235,31 @@ public:
|
|||
const concrete_out_of_bounds &other
|
||||
(static_cast <const concrete_out_of_bounds &>(base_other));
|
||||
return (out_of_bounds::subclass_equal_p (other)
|
||||
&& m_out_of_bounds_range == other.m_out_of_bounds_range);
|
||||
&& m_out_of_bounds_bits == other.m_out_of_bounds_bits);
|
||||
}
|
||||
|
||||
void maybe_add_sarif_properties (sarif_object &result_obj)
|
||||
const override
|
||||
{
|
||||
out_of_bounds::maybe_add_sarif_properties (result_obj);
|
||||
sarif_property_bag &props = result_obj.get_or_create_properties ();
|
||||
#define PROPERTY_PREFIX "gcc/analyzer/concrete_out_of_bounds/"
|
||||
props.set (PROPERTY_PREFIX "out_of_bounds_bits",
|
||||
m_out_of_bounds_bits.to_json ());
|
||||
byte_range out_of_bounds_bytes (0, 0);
|
||||
if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
|
||||
props.set (PROPERTY_PREFIX "out_of_bounds_bytes",
|
||||
out_of_bounds_bytes.to_json ());
|
||||
#undef PROPERTY_PREFIX
|
||||
}
|
||||
|
||||
bool get_out_of_bounds_bytes (byte_range *out) const
|
||||
{
|
||||
return m_out_of_bounds_bits.as_byte_range (out);
|
||||
}
|
||||
|
||||
protected:
|
||||
byte_range m_out_of_bounds_range;
|
||||
bit_range m_out_of_bounds_bits;
|
||||
};
|
||||
|
||||
/* Abstract subclass to complaing about concrete out-of-bounds
|
||||
|
|
@ -230,12 +269,18 @@ class concrete_past_the_end : public concrete_out_of_bounds
|
|||
{
|
||||
public:
|
||||
concrete_past_the_end (const region_model &model,
|
||||
const region *reg, tree diag_arg, byte_range range,
|
||||
tree byte_bound,
|
||||
const region *reg, tree diag_arg, bit_range range,
|
||||
tree bit_bound,
|
||||
const svalue *sval_hint)
|
||||
: concrete_out_of_bounds (model, reg, diag_arg, range, sval_hint),
|
||||
m_byte_bound (byte_bound)
|
||||
{}
|
||||
m_bit_bound (bit_bound),
|
||||
m_byte_bound (NULL_TREE)
|
||||
{
|
||||
if (m_bit_bound && TREE_CODE (m_bit_bound) == INTEGER_CST)
|
||||
m_byte_bound
|
||||
= wide_int_to_tree (size_type_node,
|
||||
wi::to_offset (m_bit_bound) >> LOG2_BITS_PER_UNIT);
|
||||
}
|
||||
|
||||
bool
|
||||
subclass_equal_p (const pending_diagnostic &base_other) const final override
|
||||
|
|
@ -243,8 +288,8 @@ public:
|
|||
const concrete_past_the_end &other
|
||||
(static_cast <const concrete_past_the_end &>(base_other));
|
||||
return (concrete_out_of_bounds::subclass_equal_p (other)
|
||||
&& pending_diagnostic::same_tree_p (m_byte_bound,
|
||||
other.m_byte_bound));
|
||||
&& pending_diagnostic::same_tree_p (m_bit_bound,
|
||||
other.m_bit_bound));
|
||||
}
|
||||
|
||||
void add_region_creation_events (const region *,
|
||||
|
|
@ -259,7 +304,21 @@ public:
|
|||
*this));
|
||||
}
|
||||
|
||||
void maybe_add_sarif_properties (sarif_object &result_obj)
|
||||
const final override
|
||||
{
|
||||
concrete_out_of_bounds::maybe_add_sarif_properties (result_obj);
|
||||
sarif_property_bag &props = result_obj.get_or_create_properties ();
|
||||
#define PROPERTY_PREFIX "gcc/analyzer/concrete_past_the_end/"
|
||||
props.set (PROPERTY_PREFIX "bit_bound",
|
||||
tree_to_json (m_bit_bound));
|
||||
props.set (PROPERTY_PREFIX "byte_bound",
|
||||
tree_to_json (m_byte_bound));
|
||||
#undef PROPERTY_PREFIX
|
||||
}
|
||||
|
||||
protected:
|
||||
tree m_bit_bound;
|
||||
tree m_byte_bound;
|
||||
};
|
||||
|
||||
|
|
@ -270,9 +329,9 @@ class concrete_buffer_overflow : public concrete_past_the_end
|
|||
public:
|
||||
concrete_buffer_overflow (const region_model &model,
|
||||
const region *reg, tree diag_arg,
|
||||
byte_range range, tree byte_bound,
|
||||
bit_range range, tree bit_bound,
|
||||
const svalue *sval_hint)
|
||||
: concrete_past_the_end (model, reg, diag_arg, range, byte_bound, sval_hint)
|
||||
: concrete_past_the_end (model, reg, diag_arg, range, bit_bound, sval_hint)
|
||||
{}
|
||||
|
||||
const char *get_kind () const final override
|
||||
|
|
@ -301,23 +360,44 @@ public:
|
|||
|
||||
if (warned)
|
||||
{
|
||||
if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
|
||||
if (wi::fits_uhwi_p (m_out_of_bounds_bits.m_size_in_bits))
|
||||
{
|
||||
unsigned HOST_WIDE_INT num_bad_bytes
|
||||
= m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
|
||||
if (m_diag_arg)
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"write of %wu byte to beyond the end of %qE",
|
||||
"write of %wu bytes to beyond the end of %qE",
|
||||
num_bad_bytes,
|
||||
m_diag_arg);
|
||||
unsigned HOST_WIDE_INT num_bad_bits
|
||||
= m_out_of_bounds_bits.m_size_in_bits.to_uhwi ();
|
||||
if (num_bad_bits % BITS_PER_UNIT == 0)
|
||||
{
|
||||
unsigned HOST_WIDE_INT num_bad_bytes
|
||||
= num_bad_bits / BITS_PER_UNIT;
|
||||
if (m_diag_arg)
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"write of %wu byte to beyond the end of %qE",
|
||||
"write of %wu bytes to beyond the end of %qE",
|
||||
num_bad_bytes,
|
||||
m_diag_arg);
|
||||
else
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"write of %wu byte to beyond the end of the region",
|
||||
"write of %wu bytes to beyond the end of the region",
|
||||
num_bad_bytes);
|
||||
}
|
||||
else
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"write of %wu byte to beyond the end of the region",
|
||||
"write of %wu bytes to beyond the end of the region",
|
||||
num_bad_bytes);
|
||||
{
|
||||
if (m_diag_arg)
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bits,
|
||||
"write of %wu bit to beyond the end of %qE",
|
||||
"write of %wu bits to beyond the end of %qE",
|
||||
num_bad_bits,
|
||||
m_diag_arg);
|
||||
else
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bits,
|
||||
"write of %wu bit to beyond the end of the region",
|
||||
"write of %wu bits to beyond the end of the region",
|
||||
num_bad_bits);
|
||||
}
|
||||
}
|
||||
else if (m_diag_arg)
|
||||
inform (ctxt.get_location (),
|
||||
|
|
@ -331,10 +411,23 @@ public:
|
|||
}
|
||||
|
||||
label_text describe_final_event (const evdesc::final_event &ev)
|
||||
final override
|
||||
final override
|
||||
{
|
||||
byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
|
||||
byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
|
||||
if (m_byte_bound || !m_bit_bound)
|
||||
{
|
||||
byte_range out_of_bounds_bytes (0, 0);
|
||||
if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
|
||||
return describe_final_event_as_bytes (ev, out_of_bounds_bytes);
|
||||
}
|
||||
return describe_final_event_as_bits (ev);
|
||||
}
|
||||
|
||||
label_text
|
||||
describe_final_event_as_bytes (const evdesc::final_event &ev,
|
||||
const byte_range &out_of_bounds_bytes)
|
||||
{
|
||||
byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
|
||||
byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
|
|
@ -345,10 +438,10 @@ public:
|
|||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
|
||||
" ends at byte %E", start_buf, m_diag_arg,
|
||||
m_byte_bound);
|
||||
m_byte_bound);
|
||||
return ev.formatted_print ("out-of-bounds write at byte %s but region"
|
||||
" ends at byte %E", start_buf,
|
||||
m_byte_bound);
|
||||
m_byte_bound);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -363,6 +456,38 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
label_text describe_final_event_as_bits (const evdesc::final_event &ev)
|
||||
{
|
||||
bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
|
||||
bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (end, end_buf, SIGNED);
|
||||
|
||||
if (start == end)
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds write at bit %s but %qE"
|
||||
" ends at bit %E", start_buf, m_diag_arg,
|
||||
m_bit_bound);
|
||||
return ev.formatted_print ("out-of-bounds write at bit %s but region"
|
||||
" ends at bit %E", start_buf,
|
||||
m_bit_bound);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds write from bit %s till"
|
||||
" bit %s but %qE ends at bit %E",
|
||||
start_buf, end_buf, m_diag_arg,
|
||||
m_bit_bound);
|
||||
return ev.formatted_print ("out-of-bounds write from bit %s till"
|
||||
" bit %s but region ends at bit %E",
|
||||
start_buf, end_buf, m_bit_bound);
|
||||
}
|
||||
}
|
||||
|
||||
enum access_direction get_dir () const final override { return DIR_WRITE; }
|
||||
};
|
||||
|
||||
|
|
@ -373,8 +498,8 @@ class concrete_buffer_over_read : public concrete_past_the_end
|
|||
public:
|
||||
concrete_buffer_over_read (const region_model &model,
|
||||
const region *reg, tree diag_arg,
|
||||
byte_range range, tree byte_bound)
|
||||
: concrete_past_the_end (model, reg, diag_arg, range, byte_bound, NULL)
|
||||
bit_range range, tree bit_bound)
|
||||
: concrete_past_the_end (model, reg, diag_arg, range, bit_bound, NULL)
|
||||
{}
|
||||
|
||||
const char *get_kind () const final override
|
||||
|
|
@ -401,23 +526,44 @@ public:
|
|||
|
||||
if (warned)
|
||||
{
|
||||
if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
|
||||
if (wi::fits_uhwi_p (m_out_of_bounds_bits.m_size_in_bits))
|
||||
{
|
||||
unsigned HOST_WIDE_INT num_bad_bytes
|
||||
= m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
|
||||
if (m_diag_arg)
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"read of %wu byte from after the end of %qE",
|
||||
"read of %wu bytes from after the end of %qE",
|
||||
num_bad_bytes,
|
||||
m_diag_arg);
|
||||
unsigned HOST_WIDE_INT num_bad_bits
|
||||
= m_out_of_bounds_bits.m_size_in_bits.to_uhwi ();
|
||||
if (num_bad_bits % BITS_PER_UNIT == 0)
|
||||
{
|
||||
unsigned HOST_WIDE_INT num_bad_bytes
|
||||
= num_bad_bits / BITS_PER_UNIT;
|
||||
if (m_diag_arg)
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"read of %wu byte from after the end of %qE",
|
||||
"read of %wu bytes from after the end of %qE",
|
||||
num_bad_bytes,
|
||||
m_diag_arg);
|
||||
else
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"read of %wu byte from after the end of the region",
|
||||
"read of %wu bytes from after the end of the region",
|
||||
num_bad_bytes);
|
||||
}
|
||||
else
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bytes,
|
||||
"read of %wu byte from after the end of the region",
|
||||
"read of %wu bytes from after the end of the region",
|
||||
num_bad_bytes);
|
||||
{
|
||||
if (m_diag_arg)
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bits,
|
||||
"read of %wu bit from after the end of %qE",
|
||||
"read of %wu bits from after the end of %qE",
|
||||
num_bad_bits,
|
||||
m_diag_arg);
|
||||
else
|
||||
inform_n (ctxt.get_location (),
|
||||
num_bad_bits,
|
||||
"read of %wu bit from after the end of the region",
|
||||
"read of %wu bits from after the end of the region",
|
||||
num_bad_bits);
|
||||
}
|
||||
}
|
||||
else if (m_diag_arg)
|
||||
inform (ctxt.get_location (),
|
||||
|
|
@ -431,10 +577,23 @@ public:
|
|||
}
|
||||
|
||||
label_text describe_final_event (const evdesc::final_event &ev)
|
||||
final override
|
||||
final override
|
||||
{
|
||||
byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
|
||||
byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
|
||||
if (m_byte_bound || !m_bit_bound)
|
||||
{
|
||||
byte_range out_of_bounds_bytes (0, 0);
|
||||
if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
|
||||
return describe_final_event_as_bytes (ev, out_of_bounds_bytes);
|
||||
}
|
||||
return describe_final_event_as_bits (ev);
|
||||
}
|
||||
|
||||
label_text
|
||||
describe_final_event_as_bytes (const evdesc::final_event &ev,
|
||||
const byte_range &out_of_bounds_bytes)
|
||||
{
|
||||
byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
|
||||
byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
|
|
@ -463,6 +622,38 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
label_text describe_final_event_as_bits (const evdesc::final_event &ev)
|
||||
{
|
||||
bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
|
||||
bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (end, end_buf, SIGNED);
|
||||
|
||||
if (start == end)
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds read at bit %s but %qE"
|
||||
" ends at bit %E", start_buf, m_diag_arg,
|
||||
m_bit_bound);
|
||||
return ev.formatted_print ("out-of-bounds read at bit %s but region"
|
||||
" ends at bit %E", start_buf,
|
||||
m_bit_bound);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds read from bit %s till"
|
||||
" bit %s but %qE ends at bit %E",
|
||||
start_buf, end_buf, m_diag_arg,
|
||||
m_bit_bound);
|
||||
return ev.formatted_print ("out-of-bounds read from bit %s till"
|
||||
" bit %s but region ends at bit %E",
|
||||
start_buf, end_buf, m_bit_bound);
|
||||
}
|
||||
}
|
||||
|
||||
enum access_direction get_dir () const final override { return DIR_READ; }
|
||||
};
|
||||
|
||||
|
|
@ -473,7 +664,7 @@ class concrete_buffer_underwrite : public concrete_out_of_bounds
|
|||
public:
|
||||
concrete_buffer_underwrite (const region_model &model,
|
||||
const region *reg, tree diag_arg,
|
||||
byte_range range,
|
||||
bit_range range,
|
||||
const svalue *sval_hint)
|
||||
: concrete_out_of_bounds (model, reg, diag_arg, range, sval_hint)
|
||||
{}
|
||||
|
|
@ -505,10 +696,20 @@ public:
|
|||
}
|
||||
|
||||
label_text describe_final_event (const evdesc::final_event &ev)
|
||||
final override
|
||||
final override
|
||||
{
|
||||
byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
|
||||
byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
|
||||
byte_range out_of_bounds_bytes (0, 0);
|
||||
if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
|
||||
return describe_final_event_as_bytes (ev, out_of_bounds_bytes);
|
||||
return describe_final_event_as_bits (ev);
|
||||
}
|
||||
|
||||
label_text
|
||||
describe_final_event_as_bytes (const evdesc::final_event &ev,
|
||||
const byte_range &out_of_bounds_bytes)
|
||||
{
|
||||
byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
|
||||
byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
|
|
@ -518,8 +719,8 @@ public:
|
|||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
|
||||
" starts at byte 0", start_buf,
|
||||
m_diag_arg);
|
||||
" starts at byte 0",
|
||||
start_buf, m_diag_arg);
|
||||
return ev.formatted_print ("out-of-bounds write at byte %s but region"
|
||||
" starts at byte 0", start_buf);
|
||||
}
|
||||
|
|
@ -535,6 +736,37 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
label_text
|
||||
describe_final_event_as_bits (const evdesc::final_event &ev)
|
||||
{
|
||||
bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
|
||||
bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (end, end_buf, SIGNED);
|
||||
|
||||
if (start == end)
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds write at bit %s but %qE"
|
||||
" starts at bit 0",
|
||||
start_buf, m_diag_arg);
|
||||
return ev.formatted_print ("out-of-bounds write at bit %s but region"
|
||||
" starts at bit 0", start_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds write from bit %s till"
|
||||
" bit %s but %qE starts at bit 0",
|
||||
start_buf, end_buf, m_diag_arg);
|
||||
return ev.formatted_print ("out-of-bounds write from bit %s till"
|
||||
" bit %s but region starts at bit 0",
|
||||
start_buf, end_buf);;
|
||||
}
|
||||
}
|
||||
|
||||
enum access_direction get_dir () const final override { return DIR_WRITE; }
|
||||
};
|
||||
|
||||
|
|
@ -545,7 +777,7 @@ class concrete_buffer_under_read : public concrete_out_of_bounds
|
|||
public:
|
||||
concrete_buffer_under_read (const region_model &model,
|
||||
const region *reg, tree diag_arg,
|
||||
byte_range range)
|
||||
bit_range range)
|
||||
: concrete_out_of_bounds (model, reg, diag_arg, range, NULL)
|
||||
{}
|
||||
|
||||
|
|
@ -576,10 +808,20 @@ public:
|
|||
}
|
||||
|
||||
label_text describe_final_event (const evdesc::final_event &ev)
|
||||
final override
|
||||
final override
|
||||
{
|
||||
byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
|
||||
byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
|
||||
byte_range out_of_bounds_bytes (0, 0);
|
||||
if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
|
||||
return describe_final_event_as_bytes (ev, out_of_bounds_bytes);
|
||||
return describe_final_event_as_bits (ev);
|
||||
}
|
||||
|
||||
label_text
|
||||
describe_final_event_as_bytes (const evdesc::final_event &ev,
|
||||
const byte_range &out_of_bounds_bytes)
|
||||
{
|
||||
byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
|
||||
byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
|
|
@ -606,6 +848,36 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
label_text describe_final_event_as_bits (const evdesc::final_event &ev)
|
||||
{
|
||||
bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
|
||||
bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
|
||||
char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (start, start_buf, SIGNED);
|
||||
char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
|
||||
print_dec (end, end_buf, SIGNED);
|
||||
|
||||
if (start == end)
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds read at bit %s but %qE"
|
||||
" starts at bit 0", start_buf,
|
||||
m_diag_arg);
|
||||
return ev.formatted_print ("out-of-bounds read at bit %s but region"
|
||||
" starts at bit 0", start_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_diag_arg)
|
||||
return ev.formatted_print ("out-of-bounds read from bit %s till"
|
||||
" bit %s but %qE starts at bit 0",
|
||||
start_buf, end_buf, m_diag_arg);
|
||||
return ev.formatted_print ("out-of-bounds read from bit %s till"
|
||||
" bit %s but region starts at bit 0",
|
||||
start_buf, end_buf);;
|
||||
}
|
||||
}
|
||||
|
||||
enum access_direction get_dir () const final override { return DIR_READ; }
|
||||
};
|
||||
|
||||
|
|
@ -636,6 +908,18 @@ public:
|
|||
&& pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
|
||||
}
|
||||
|
||||
void maybe_add_sarif_properties (sarif_object &result_obj)
|
||||
const final override
|
||||
{
|
||||
out_of_bounds::maybe_add_sarif_properties (result_obj);
|
||||
sarif_property_bag &props = result_obj.get_or_create_properties ();
|
||||
#define PROPERTY_PREFIX "gcc/analyzer/symbolic_past_the_end/"
|
||||
props.set (PROPERTY_PREFIX "offset", tree_to_json (m_offset));
|
||||
props.set (PROPERTY_PREFIX "num_bytes", tree_to_json (m_num_bytes));
|
||||
props.set (PROPERTY_PREFIX "capacity", tree_to_json (m_capacity));
|
||||
#undef PROPERTY_PREFIX
|
||||
}
|
||||
|
||||
protected:
|
||||
tree m_offset;
|
||||
tree m_num_bytes;
|
||||
|
|
@ -955,16 +1239,16 @@ region_model::check_region_bounds (const region *reg,
|
|||
region_offset reg_offset = reg->get_offset (m_mgr);
|
||||
const region *base_reg = reg_offset.get_base_region ();
|
||||
|
||||
/* Find out how many bytes were accessed. */
|
||||
const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
|
||||
tree num_bytes_tree = maybe_get_integer_cst_tree (num_bytes_sval);
|
||||
/* Bail out if 0 bytes are accessed. */
|
||||
if (num_bytes_tree && zerop (num_bytes_tree))
|
||||
/* Find out how many bits were accessed. */
|
||||
const svalue *num_bits_sval = reg->get_bit_size_sval (m_mgr);
|
||||
tree num_bits_tree = maybe_get_integer_cst_tree (num_bits_sval);
|
||||
/* Bail out if 0 bits are accessed. */
|
||||
if (num_bits_tree && zerop (num_bits_tree))
|
||||
return true;
|
||||
|
||||
/* Get the capacity of the buffer. */
|
||||
const svalue *capacity = get_capacity (base_reg);
|
||||
tree cst_capacity_tree = maybe_get_integer_cst_tree (capacity);
|
||||
/* Get the capacity of the buffer (in bytes). */
|
||||
const svalue *byte_capacity = get_capacity (base_reg);
|
||||
tree cst_byte_capacity_tree = maybe_get_integer_cst_tree (byte_capacity);
|
||||
|
||||
/* The constant offset from a pointer is represented internally as a sizetype
|
||||
but should be interpreted as a signed value here. The statement below
|
||||
|
|
@ -973,36 +1257,39 @@ region_model::check_region_bounds (const region *reg,
|
|||
|
||||
For example, this is needed for out-of-bounds-3.c test1 to pass when
|
||||
compiled with a 64-bit gcc build targeting 32-bit systems. */
|
||||
byte_offset_t offset;
|
||||
bit_offset_t bit_offset;
|
||||
if (!reg_offset.symbolic_p ())
|
||||
offset = wi::sext (reg_offset.get_bit_offset () >> LOG2_BITS_PER_UNIT,
|
||||
TYPE_PRECISION (size_type_node));
|
||||
bit_offset = wi::sext (reg_offset.get_bit_offset (),
|
||||
TYPE_PRECISION (size_type_node));
|
||||
|
||||
/* If any of the base region, the offset, or the number of bytes accessed
|
||||
are symbolic, we have to reason about symbolic values. */
|
||||
if (base_reg->symbolic_p () || reg_offset.symbolic_p () || !num_bytes_tree)
|
||||
if (base_reg->symbolic_p () || reg_offset.symbolic_p () || !num_bits_tree)
|
||||
{
|
||||
const svalue* byte_offset_sval;
|
||||
if (!reg_offset.symbolic_p ())
|
||||
{
|
||||
tree offset_tree = wide_int_to_tree (integer_type_node, offset);
|
||||
tree byte_offset_tree
|
||||
= wide_int_to_tree (integer_type_node,
|
||||
bit_offset >> LOG2_BITS_PER_UNIT);
|
||||
byte_offset_sval
|
||||
= m_mgr->get_or_create_constant_svalue (offset_tree);
|
||||
= m_mgr->get_or_create_constant_svalue (byte_offset_tree);
|
||||
}
|
||||
else
|
||||
byte_offset_sval = reg_offset.get_symbolic_byte_offset ();
|
||||
const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
|
||||
return check_symbolic_bounds (base_reg, byte_offset_sval, num_bytes_sval,
|
||||
capacity, dir, sval_hint, ctxt);
|
||||
byte_capacity, dir, sval_hint, ctxt);
|
||||
}
|
||||
|
||||
/* Otherwise continue to check with concrete values. */
|
||||
byte_range out (0, 0);
|
||||
bit_range bits_outside (0, 0);
|
||||
bool oob_safe = true;
|
||||
/* NUM_BYTES_TREE should always be interpreted as unsigned. */
|
||||
byte_offset_t num_bytes_unsigned = wi::to_offset (num_bytes_tree);
|
||||
byte_range read_bytes (offset, num_bytes_unsigned);
|
||||
/* If read_bytes has a subset < 0, we do have an underwrite. */
|
||||
if (read_bytes.falls_short_of_p (0, &out))
|
||||
/* NUM_BITS_TREE should always be interpreted as unsigned. */
|
||||
bit_offset_t num_bits_unsigned = wi::to_offset (num_bits_tree);
|
||||
bit_range read_bits (bit_offset, num_bits_unsigned);
|
||||
/* If read_bits has a subset < 0, we do have an underwrite. */
|
||||
if (read_bits.falls_short_of_p (0, &bits_outside))
|
||||
{
|
||||
tree diag_arg = get_representative_tree (base_reg);
|
||||
switch (dir)
|
||||
|
|
@ -1014,13 +1301,13 @@ region_model::check_region_bounds (const region *reg,
|
|||
gcc_assert (sval_hint == nullptr);
|
||||
ctxt->warn (make_unique<concrete_buffer_under_read> (*this, reg,
|
||||
diag_arg,
|
||||
out));
|
||||
bits_outside));
|
||||
oob_safe = false;
|
||||
break;
|
||||
case DIR_WRITE:
|
||||
ctxt->warn (make_unique<concrete_buffer_underwrite> (*this,
|
||||
reg, diag_arg,
|
||||
out,
|
||||
bits_outside,
|
||||
sval_hint));
|
||||
oob_safe = false;
|
||||
break;
|
||||
|
|
@ -1030,15 +1317,15 @@ region_model::check_region_bounds (const region *reg,
|
|||
/* For accesses past the end, we do need a concrete capacity. No need to
|
||||
do a symbolic check here because the inequality check does not reason
|
||||
whether constants are greater than symbolic values. */
|
||||
if (!cst_capacity_tree)
|
||||
return oob_safe;
|
||||
if (!cst_byte_capacity_tree)
|
||||
return oob_safe;
|
||||
|
||||
byte_range buffer (0, wi::to_offset (cst_capacity_tree));
|
||||
/* If READ_BYTES exceeds BUFFER, we do have an overflow. */
|
||||
if (read_bytes.exceeds_p (buffer, &out))
|
||||
bit_range buffer (0, wi::to_offset (cst_byte_capacity_tree) * BITS_PER_UNIT);
|
||||
/* If READ_BITS exceeds BUFFER, we do have an overflow. */
|
||||
if (read_bits.exceeds_p (buffer, &bits_outside))
|
||||
{
|
||||
tree byte_bound = wide_int_to_tree (size_type_node,
|
||||
buffer.get_next_byte_offset ());
|
||||
tree bit_bound = wide_int_to_tree (size_type_node,
|
||||
buffer.get_next_bit_offset ());
|
||||
tree diag_arg = get_representative_tree (base_reg);
|
||||
|
||||
switch (dir)
|
||||
|
|
@ -1050,13 +1337,15 @@ region_model::check_region_bounds (const region *reg,
|
|||
gcc_assert (sval_hint == nullptr);
|
||||
ctxt->warn (make_unique<concrete_buffer_over_read> (*this,
|
||||
reg, diag_arg,
|
||||
out, byte_bound));
|
||||
bits_outside,
|
||||
bit_bound));
|
||||
oob_safe = false;
|
||||
break;
|
||||
case DIR_WRITE:
|
||||
ctxt->warn (make_unique<concrete_buffer_overflow> (*this,
|
||||
reg, diag_arg,
|
||||
out, byte_bound,
|
||||
bits_outside,
|
||||
bit_bound,
|
||||
sval_hint));
|
||||
oob_safe = false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ struct infinite_loop
|
|||
{
|
||||
infinite_loop (const exploded_node &enode,
|
||||
location_t loc,
|
||||
std::vector<const exploded_edge *> eedges,
|
||||
std::vector<const exploded_edge *> &&eedges,
|
||||
logger *logger)
|
||||
: m_enode (enode),
|
||||
m_loc (loc),
|
||||
|
|
@ -423,9 +423,9 @@ starts_infinite_loop_p (const exploded_node &enode,
|
|||
free (filename);
|
||||
}
|
||||
return ::make_unique<infinite_loop> (enode,
|
||||
first_loc,
|
||||
eedges,
|
||||
logger);
|
||||
first_loc,
|
||||
std::move (eedges),
|
||||
logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -211,6 +211,31 @@ region_to_value_map::dump (bool simple) const
|
|||
pp_flush (&pp);
|
||||
}
|
||||
|
||||
/* Generate a JSON value for this region_to_value_map.
|
||||
This is intended for debugging the analyzer rather than
|
||||
serialization. */
|
||||
|
||||
json::object *
|
||||
region_to_value_map::to_json () const
|
||||
{
|
||||
json::object *map_obj = new json::object ();
|
||||
|
||||
auto_vec<const region *> regs;
|
||||
for (iterator iter = begin (); iter != end (); ++iter)
|
||||
regs.safe_push ((*iter).first);
|
||||
regs.qsort (region::cmp_ptr_ptr);
|
||||
|
||||
unsigned i;
|
||||
const region *reg;
|
||||
FOR_EACH_VEC_ELT (regs, i, reg)
|
||||
{
|
||||
label_text reg_desc = reg->get_desc ();
|
||||
const svalue *sval = *get (reg);
|
||||
map_obj->set (reg_desc.get (), sval->to_json ());
|
||||
}
|
||||
|
||||
return map_obj;
|
||||
}
|
||||
|
||||
/* Attempt to merge THIS with OTHER, writing the result
|
||||
to OUT.
|
||||
|
|
@ -429,6 +454,22 @@ region_model::debug () const
|
|||
dump (true);
|
||||
}
|
||||
|
||||
/* Generate a JSON value for this region_model.
|
||||
This is intended for debugging the analyzer rather than
|
||||
serialization. */
|
||||
|
||||
json::object *
|
||||
region_model::to_json () const
|
||||
{
|
||||
json::object *model_obj = new json::object ();
|
||||
model_obj->set ("store", m_store.to_json ());
|
||||
model_obj->set ("constraints", m_constraints->to_json ());
|
||||
if (m_current_frame)
|
||||
model_obj->set ("current_frame", m_current_frame->to_json ());
|
||||
model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ());
|
||||
return model_obj;
|
||||
}
|
||||
|
||||
/* Assert that this object is valid. */
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -175,6 +175,8 @@ public:
|
|||
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool can_merge_with_p (const region_to_value_map &other,
|
||||
region_to_value_map *out) const;
|
||||
|
||||
|
|
@ -278,6 +280,8 @@ class region_model
|
|||
|
||||
void debug () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
void validate () const;
|
||||
|
||||
void canonicalize ();
|
||||
|
|
|
|||
|
|
@ -757,6 +757,24 @@ int_size_in_bits (const_tree type, bit_size_t *out)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Base implementation of region::get_bit_size_sval vfunc. */
|
||||
|
||||
const svalue *
|
||||
region::get_bit_size_sval (region_model_manager *mgr) const
|
||||
{
|
||||
tree type = get_type ();
|
||||
|
||||
/* Bail out e.g. for heap-allocated regions. */
|
||||
if (!type)
|
||||
return mgr->get_or_create_unknown_svalue (size_type_node);
|
||||
|
||||
bit_size_t bits;
|
||||
if (!int_size_in_bits (type, &bits))
|
||||
return mgr->get_or_create_unknown_svalue (size_type_node);
|
||||
|
||||
return mgr->get_or_create_int_cst (size_type_node, bits);
|
||||
}
|
||||
|
||||
/* If the size of this region (in bits) is known statically, write it to *OUT
|
||||
and return true.
|
||||
Otherwise return false. */
|
||||
|
|
@ -1933,6 +1951,15 @@ offset_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
const svalue *
|
||||
offset_region::get_bit_offset (region_model_manager *mgr) const
|
||||
{
|
||||
const svalue *bits_per_byte_sval
|
||||
= mgr->get_or_create_int_cst (size_type_node, BITS_PER_UNIT);
|
||||
return mgr->get_or_create_binop (size_type_node, MULT_EXPR,
|
||||
m_byte_offset, bits_per_byte_sval);
|
||||
}
|
||||
|
||||
/* Implementation of region::get_relative_concrete_offset vfunc
|
||||
for offset_region. */
|
||||
|
||||
|
|
@ -1987,6 +2014,30 @@ offset_region::get_byte_size_sval (region_model_manager *mgr) const
|
|||
return region::get_byte_size_sval (mgr);
|
||||
}
|
||||
|
||||
/* Implementation of region::get_bit_size_sval vfunc for offset_region. */
|
||||
|
||||
const svalue *
|
||||
offset_region::get_bit_size_sval (region_model_manager *mgr) const
|
||||
{
|
||||
tree offset_cst = get_bit_offset (mgr)->maybe_get_constant ();
|
||||
bit_size_t bit_size;
|
||||
/* If the offset points in the middle of the region,
|
||||
return the remaining bits. */
|
||||
if (get_bit_size (&bit_size) && offset_cst)
|
||||
{
|
||||
bit_size_t offset = wi::to_offset (offset_cst);
|
||||
bit_range r (0, bit_size);
|
||||
if (r.contains_p (offset))
|
||||
{
|
||||
tree remaining_bit_size = wide_int_to_tree (size_type_node,
|
||||
bit_size - offset);
|
||||
return mgr->get_or_create_constant_svalue (remaining_bit_size);
|
||||
}
|
||||
}
|
||||
|
||||
return region::get_bit_size_sval (mgr);
|
||||
}
|
||||
|
||||
/* class sized_region : public region. */
|
||||
|
||||
/* Implementation of region::accept vfunc for sized_region. */
|
||||
|
|
@ -2047,6 +2098,17 @@ sized_region::get_bit_size (bit_size_t *out) const
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Implementation of region::get_bit_size_sval vfunc for sized_region. */
|
||||
|
||||
const svalue *
|
||||
sized_region::get_bit_size_sval (region_model_manager *mgr) const
|
||||
{
|
||||
const svalue *bits_per_byte_sval
|
||||
= mgr->get_or_create_int_cst (size_type_node, BITS_PER_UNIT);
|
||||
return mgr->get_or_create_binop (size_type_node, MULT_EXPR,
|
||||
m_byte_size_sval, bits_per_byte_sval);
|
||||
}
|
||||
|
||||
/* class cast_region : public region. */
|
||||
|
||||
/* Implementation of region::accept vfunc for cast_region. */
|
||||
|
|
@ -2198,6 +2260,15 @@ bit_range_region::get_byte_size_sval (region_model_manager *mgr) const
|
|||
return mgr->get_or_create_int_cst (size_type_node, num_bytes);
|
||||
}
|
||||
|
||||
/* Implementation of region::get_bit_size_sval vfunc for bit_range_region. */
|
||||
|
||||
const svalue *
|
||||
bit_range_region::get_bit_size_sval (region_model_manager *mgr) const
|
||||
{
|
||||
return mgr->get_or_create_int_cst (size_type_node,
|
||||
m_bits.m_size_in_bits);
|
||||
}
|
||||
|
||||
/* Implementation of region::get_relative_concrete_offset vfunc for
|
||||
bit_range_region. */
|
||||
|
||||
|
|
|
|||
|
|
@ -199,6 +199,10 @@ public:
|
|||
(which could be "unknown"). */
|
||||
virtual const svalue *get_byte_size_sval (region_model_manager *mgr) const;
|
||||
|
||||
/* Get a symbolic value describing the size of this region in bits
|
||||
(which could be "unknown"). */
|
||||
virtual const svalue *get_bit_size_sval (region_model_manager *mgr) const;
|
||||
|
||||
/* Attempt to get the offset in bits of this region relative to its parent.
|
||||
If successful, return true and write to *OUT.
|
||||
Otherwise return false. */
|
||||
|
|
@ -969,13 +973,15 @@ public:
|
|||
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
|
||||
|
||||
const svalue *get_byte_offset () const { return m_byte_offset; }
|
||||
const svalue *get_bit_offset (region_model_manager *mgr) const;
|
||||
|
||||
bool get_relative_concrete_offset (bit_offset_t *out) const final override;
|
||||
const svalue *get_relative_symbolic_offset (region_model_manager *mgr)
|
||||
const final override;
|
||||
const svalue * get_byte_size_sval (region_model_manager *mgr)
|
||||
const final override;
|
||||
|
||||
const svalue * get_bit_size_sval (region_model_manager *mgr)
|
||||
const final override;
|
||||
|
||||
private:
|
||||
const svalue *m_byte_offset;
|
||||
|
|
@ -1070,6 +1076,9 @@ public:
|
|||
return m_byte_size_sval;
|
||||
}
|
||||
|
||||
const svalue *
|
||||
get_bit_size_sval (region_model_manager *) const final override;
|
||||
|
||||
private:
|
||||
const svalue *m_byte_size_sval;
|
||||
};
|
||||
|
|
@ -1304,6 +1313,7 @@ public:
|
|||
bool get_byte_size (byte_size_t *out) const final override;
|
||||
bool get_bit_size (bit_size_t *out) const final override;
|
||||
const svalue *get_byte_size_sval (region_model_manager *mgr) const final override;
|
||||
const svalue *get_bit_size_sval (region_model_manager *mgr) const final override;
|
||||
bool get_relative_concrete_offset (bit_offset_t *out) const final override;
|
||||
const svalue *get_relative_symbolic_offset (region_model_manager *mgr)
|
||||
const final override;
|
||||
|
|
|
|||
|
|
@ -270,13 +270,13 @@ private:
|
|||
/* fileptr_state_machine's ctor. */
|
||||
|
||||
fileptr_state_machine::fileptr_state_machine (logger *logger)
|
||||
: state_machine ("file", logger)
|
||||
: state_machine ("file", logger),
|
||||
m_unchecked (add_state ("unchecked")),
|
||||
m_null (add_state ("null")),
|
||||
m_nonnull (add_state ("nonnull")),
|
||||
m_closed (add_state ("closed")),
|
||||
m_stop (add_state ("stop"))
|
||||
{
|
||||
m_unchecked = add_state ("unchecked");
|
||||
m_null = add_state ("null");
|
||||
m_nonnull = add_state ("nonnull");
|
||||
m_closed = add_state ("closed");
|
||||
m_stop = add_state ("stop");
|
||||
}
|
||||
|
||||
/* Get a set of functions that are known to take a FILE * that must be open,
|
||||
|
|
|
|||
|
|
@ -161,10 +161,10 @@ private:
|
|||
/* sensitive_state_machine's ctor. */
|
||||
|
||||
sensitive_state_machine::sensitive_state_machine (logger *logger)
|
||||
: state_machine ("sensitive", logger)
|
||||
: state_machine ("sensitive", logger),
|
||||
m_sensitive (add_state ("sensitive")),
|
||||
m_stop (add_state ("stop"))
|
||||
{
|
||||
m_sensitive = add_state ("sensitive");
|
||||
m_stop = add_state ("stop");
|
||||
}
|
||||
|
||||
/* Warn about an exposure at NODE and STMT if ARG is in the "sensitive"
|
||||
|
|
|
|||
|
|
@ -182,10 +182,10 @@ private:
|
|||
/* signal_state_machine's ctor. */
|
||||
|
||||
signal_state_machine::signal_state_machine (logger *logger)
|
||||
: state_machine ("signal", logger)
|
||||
: state_machine ("signal", logger),
|
||||
m_in_signal_handler (add_state ("in_signal_handler")),
|
||||
m_stop (add_state ("stop"))
|
||||
{
|
||||
m_in_signal_handler = add_state ("in_signal_handler");
|
||||
m_stop = add_state ("stop");
|
||||
}
|
||||
|
||||
/* Update MODEL for edges that simulate HANDLER_FUN being called as
|
||||
|
|
|
|||
|
|
@ -830,13 +830,13 @@ private:
|
|||
/* taint_state_machine's ctor. */
|
||||
|
||||
taint_state_machine::taint_state_machine (logger *logger)
|
||||
: state_machine ("taint", logger)
|
||||
: state_machine ("taint", logger),
|
||||
m_tainted (add_state ("tainted")),
|
||||
m_has_lb (add_state ("has_lb")),
|
||||
m_has_ub (add_state ("has_ub")),
|
||||
m_stop (add_state ("stop")),
|
||||
m_tainted_control_flow (add_state ("tainted-control-flow"))
|
||||
{
|
||||
m_tainted = add_state ("tainted");
|
||||
m_has_lb = add_state ("has_lb");
|
||||
m_has_ub = add_state ("has_ub");
|
||||
m_stop = add_state ("stop");
|
||||
m_tainted_control_flow = add_state ("tainted-control-flow");
|
||||
}
|
||||
|
||||
state_machine::state_t
|
||||
|
|
|
|||
|
|
@ -235,6 +235,21 @@ bit_range::dump () const
|
|||
pp_flush (&pp);
|
||||
}
|
||||
|
||||
/* Generate a JSON value for this bit_range.
|
||||
This is intended for debugging the analyzer rather
|
||||
than serialization. */
|
||||
|
||||
json::object *
|
||||
bit_range::to_json () const
|
||||
{
|
||||
json::object *obj = new json::object ();
|
||||
obj->set ("start_bit_offset",
|
||||
bit_offset_to_json (m_start_bit_offset));
|
||||
obj->set ("size_in_bits",
|
||||
bit_offset_to_json (m_size_in_bits));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* If OTHER is a subset of this, return true and, if OUT is
|
||||
non-null, write to *OUT the relative range of OTHER within this.
|
||||
Otherwise return false. */
|
||||
|
|
@ -285,6 +300,77 @@ bit_range::intersects_p (const bit_range &other,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Return true if THIS and OTHER intersect and write the number
|
||||
of bits both buffers overlap to *OUT_NUM_OVERLAP_BITS.
|
||||
|
||||
Otherwise return false. */
|
||||
|
||||
bool
|
||||
bit_range::intersects_p (const bit_range &other,
|
||||
bit_size_t *out_num_overlap_bits) const
|
||||
{
|
||||
if (get_start_bit_offset () < other.get_next_bit_offset ()
|
||||
&& other.get_start_bit_offset () < get_next_bit_offset ())
|
||||
{
|
||||
bit_offset_t overlap_start = MAX (get_start_bit_offset (),
|
||||
other.get_start_bit_offset ());
|
||||
bit_offset_t overlap_next = MIN (get_next_bit_offset (),
|
||||
other.get_next_bit_offset ());
|
||||
gcc_assert (overlap_next > overlap_start);
|
||||
*out_num_overlap_bits = overlap_next - overlap_start;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if THIS exceeds OTHER and write the overhanging
|
||||
bit range to OUT_OVERHANGING_BIT_RANGE. */
|
||||
|
||||
bool
|
||||
bit_range::exceeds_p (const bit_range &other,
|
||||
bit_range *out_overhanging_bit_range) const
|
||||
{
|
||||
gcc_assert (!empty_p ());
|
||||
|
||||
if (other.get_next_bit_offset () < get_next_bit_offset ())
|
||||
{
|
||||
/* THIS definitely exceeds OTHER. */
|
||||
bit_offset_t start = MAX (get_start_bit_offset (),
|
||||
other.get_next_bit_offset ());
|
||||
bit_offset_t size = get_next_bit_offset () - start;
|
||||
gcc_assert (size > 0);
|
||||
out_overhanging_bit_range->m_start_bit_offset = start;
|
||||
out_overhanging_bit_range->m_size_in_bits = size;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if THIS falls short of OFFSET and write the
|
||||
bit range fallen short to OUT_FALL_SHORT_BITS. */
|
||||
|
||||
bool
|
||||
bit_range::falls_short_of_p (bit_offset_t offset,
|
||||
bit_range *out_fall_short_bits) const
|
||||
{
|
||||
gcc_assert (!empty_p ());
|
||||
|
||||
if (get_start_bit_offset () < offset)
|
||||
{
|
||||
/* THIS falls short of OFFSET. */
|
||||
bit_offset_t start = get_start_bit_offset ();
|
||||
bit_offset_t size = MIN (offset, get_next_bit_offset ()) - start;
|
||||
gcc_assert (size > 0);
|
||||
out_fall_short_bits->m_start_bit_offset = start;
|
||||
out_fall_short_bits->m_size_in_bits = size;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
bit_range::cmp (const bit_range &br1, const bit_range &br2)
|
||||
{
|
||||
|
|
@ -413,6 +499,21 @@ byte_range::dump () const
|
|||
pp_flush (&pp);
|
||||
}
|
||||
|
||||
/* Generate a JSON value for this byte_range.
|
||||
This is intended for debugging the analyzer rather
|
||||
than serialization. */
|
||||
|
||||
json::object *
|
||||
byte_range::to_json () const
|
||||
{
|
||||
json::object *obj = new json::object ();
|
||||
obj->set ("start_byte_offset",
|
||||
byte_offset_to_json (m_start_byte_offset));
|
||||
obj->set ("size_in_bytes",
|
||||
byte_offset_to_json (m_size_in_bytes));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* If OTHER is a subset of this, return true and write
|
||||
to *OUT the relative range of OTHER within this.
|
||||
Otherwise return false. */
|
||||
|
|
@ -431,77 +532,6 @@ byte_range::contains_p (const byte_range &other, byte_range *out) const
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Return true if THIS and OTHER intersect and write the number
|
||||
of bytes both buffers overlap to *OUT_NUM_OVERLAP_BYTES.
|
||||
|
||||
Otherwise return false. */
|
||||
|
||||
bool
|
||||
byte_range::intersects_p (const byte_range &other,
|
||||
byte_size_t *out_num_overlap_bytes) const
|
||||
{
|
||||
if (get_start_byte_offset () < other.get_next_byte_offset ()
|
||||
&& other.get_start_byte_offset () < get_next_byte_offset ())
|
||||
{
|
||||
byte_offset_t overlap_start = MAX (get_start_byte_offset (),
|
||||
other.get_start_byte_offset ());
|
||||
byte_offset_t overlap_next = MIN (get_next_byte_offset (),
|
||||
other.get_next_byte_offset ());
|
||||
gcc_assert (overlap_next > overlap_start);
|
||||
*out_num_overlap_bytes = overlap_next - overlap_start;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if THIS exceeds OTHER and write the overhanging
|
||||
byte range to OUT_OVERHANGING_BYTE_RANGE. */
|
||||
|
||||
bool
|
||||
byte_range::exceeds_p (const byte_range &other,
|
||||
byte_range *out_overhanging_byte_range) const
|
||||
{
|
||||
gcc_assert (!empty_p ());
|
||||
|
||||
if (other.get_next_byte_offset () < get_next_byte_offset ())
|
||||
{
|
||||
/* THIS definitely exceeds OTHER. */
|
||||
byte_offset_t start = MAX (get_start_byte_offset (),
|
||||
other.get_next_byte_offset ());
|
||||
byte_offset_t size = get_next_byte_offset () - start;
|
||||
gcc_assert (size > 0);
|
||||
out_overhanging_byte_range->m_start_byte_offset = start;
|
||||
out_overhanging_byte_range->m_size_in_bytes = size;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if THIS falls short of OFFSET and write the
|
||||
byte range fallen short to OUT_FALL_SHORT_BYTES. */
|
||||
|
||||
bool
|
||||
byte_range::falls_short_of_p (byte_offset_t offset,
|
||||
byte_range *out_fall_short_bytes) const
|
||||
{
|
||||
gcc_assert (!empty_p ());
|
||||
|
||||
if (get_start_byte_offset () < offset)
|
||||
{
|
||||
/* THIS falls short of OFFSET. */
|
||||
byte_offset_t start = get_start_byte_offset ();
|
||||
byte_offset_t size = MIN (offset, get_next_byte_offset ()) - start;
|
||||
gcc_assert (size > 0);
|
||||
out_fall_short_bytes->m_start_byte_offset = start;
|
||||
out_fall_short_bytes->m_size_in_bytes = size;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* qsort comparator for byte ranges. */
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -237,6 +237,8 @@ struct bit_range
|
|||
void dump_to_pp (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool empty_p () const
|
||||
{
|
||||
return m_size_in_bits == 0;
|
||||
|
|
@ -275,10 +277,18 @@ struct bit_range
|
|||
return (get_start_bit_offset () < other.get_next_bit_offset ()
|
||||
&& other.get_start_bit_offset () < get_next_bit_offset ());
|
||||
}
|
||||
bool intersects_p (const bit_range &other,
|
||||
bit_size_t *out_num_overlap_bits) const;
|
||||
bool intersects_p (const bit_range &other,
|
||||
bit_range *out_this,
|
||||
bit_range *out_other) const;
|
||||
|
||||
bool exceeds_p (const bit_range &other,
|
||||
bit_range *out_overhanging_bit_range) const;
|
||||
|
||||
bool falls_short_of_p (bit_offset_t offset,
|
||||
bit_range *out_fall_short_bits) const;
|
||||
|
||||
static int cmp (const bit_range &br1, const bit_range &br2);
|
||||
|
||||
bit_range operator- (bit_offset_t offset) const;
|
||||
|
|
@ -303,6 +313,8 @@ struct byte_range
|
|||
void dump_to_pp (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool empty_p () const
|
||||
{
|
||||
return m_size_in_bytes == 0;
|
||||
|
|
@ -321,15 +333,6 @@ struct byte_range
|
|||
&& m_size_in_bytes == other.m_size_in_bytes);
|
||||
}
|
||||
|
||||
bool intersects_p (const byte_range &other,
|
||||
byte_size_t *out_num_overlap_bytes) const;
|
||||
|
||||
bool exceeds_p (const byte_range &other,
|
||||
byte_range *out_overhanging_byte_range) const;
|
||||
|
||||
bool falls_short_of_p (byte_offset_t offset,
|
||||
byte_range *out_fall_short_bytes) const;
|
||||
|
||||
byte_offset_t get_start_byte_offset () const
|
||||
{
|
||||
return m_start_byte_offset;
|
||||
|
|
|
|||
|
|
@ -241,10 +241,10 @@ private:
|
|||
/* va_list_state_machine's ctor. */
|
||||
|
||||
va_list_state_machine::va_list_state_machine (logger *logger)
|
||||
: state_machine ("va_list", logger)
|
||||
: state_machine ("va_list", logger),
|
||||
m_started (add_state ("started")),
|
||||
m_ended (add_state ("ended"))
|
||||
{
|
||||
m_started = add_state ("started");
|
||||
m_ended = add_state ("ended");
|
||||
}
|
||||
|
||||
/* Implementation of the various "va_*" functions for
|
||||
|
|
|
|||
|
|
@ -675,7 +675,8 @@ decl_attributes (tree *node, tree attributes, int flags,
|
|||
options to the attribute((target(...))) list. */
|
||||
if (TREE_CODE (*node) == FUNCTION_DECL
|
||||
&& current_target_pragma
|
||||
&& targetm.target_option.valid_attribute_p (*node, NULL_TREE,
|
||||
&& targetm.target_option.valid_attribute_p (*node,
|
||||
get_identifier ("target"),
|
||||
current_target_pragma, 0))
|
||||
{
|
||||
tree cur_attr = lookup_attribute ("target", attributes);
|
||||
|
|
@ -1276,8 +1277,9 @@ make_dispatcher_decl (const tree decl)
|
|||
return func_decl;
|
||||
}
|
||||
|
||||
/* Returns true if decl is multi-versioned and DECL is the default function,
|
||||
that is it is not tagged with target specific optimization. */
|
||||
/* Returns true if DECL is multi-versioned using the target attribute, and this
|
||||
is the default version. This function can only be used for targets that do
|
||||
not support the "target_version" attribute. */
|
||||
|
||||
bool
|
||||
is_function_default_version (const tree decl)
|
||||
|
|
|
|||
|
|
@ -268,6 +268,17 @@ btf_emit_id_p (ctf_id_t id)
|
|||
&& (btf_id_map[id] <= BTF_MAX_TYPE));
|
||||
}
|
||||
|
||||
/* Return true if DTD is a forward-declared enum. The BTF representation
|
||||
of forward declared enums is not formally defined. */
|
||||
|
||||
static bool
|
||||
btf_fwd_to_enum_p (ctf_dtdef_ref dtd)
|
||||
{
|
||||
uint32_t btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
|
||||
|
||||
return (btf_kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
|
||||
}
|
||||
|
||||
/* Each BTF type can be followed additional, variable-length information
|
||||
completing the description of the type. Calculate the number of bytes
|
||||
of variable information required to encode a given type. */
|
||||
|
|
@ -753,8 +764,12 @@ btf_asm_type_ref (const char *prefix, ctf_container_ref ctfc, ctf_id_t ref_id)
|
|||
uint32_t ref_kind
|
||||
= get_btf_kind (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info));
|
||||
|
||||
const char *kind_name = btf_fwd_to_enum_p (ref_type)
|
||||
? btf_kind_name (BTF_KIND_ENUM)
|
||||
: btf_kind_name (ref_kind);
|
||||
|
||||
dw2_asm_output_data (4, ref_id, "%s: (BTF_KIND_%s '%s')",
|
||||
prefix, btf_kind_name (ref_kind),
|
||||
prefix, kind_name,
|
||||
get_btf_type_name (ref_type));
|
||||
}
|
||||
}
|
||||
|
|
@ -765,11 +780,11 @@ btf_asm_type_ref (const char *prefix, ctf_container_ref ctfc, ctf_id_t ref_id)
|
|||
static void
|
||||
btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
|
||||
{
|
||||
uint32_t btf_kind, btf_kflag, btf_vlen, btf_size_type;
|
||||
uint32_t btf_kind, btf_kflag, btf_vlen, btf_size;
|
||||
uint32_t ctf_info = dtd->dtd_data.ctti_info;
|
||||
|
||||
btf_kind = get_btf_kind (CTF_V2_INFO_KIND (ctf_info));
|
||||
btf_size_type = dtd->dtd_data.ctti_type;
|
||||
btf_size = dtd->dtd_data.ctti_size;
|
||||
btf_vlen = CTF_V2_INFO_VLEN (ctf_info);
|
||||
|
||||
/* By now any unrepresentable types have been removed. */
|
||||
|
|
@ -777,7 +792,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
|
|||
|
||||
/* Size 0 integers are redundant definitions of void. None should remain
|
||||
in the types list by this point. */
|
||||
gcc_assert (btf_kind != BTF_KIND_INT || btf_size_type >= 1);
|
||||
gcc_assert (btf_kind != BTF_KIND_INT || btf_size >= 1);
|
||||
|
||||
/* Re-encode the ctti_info to BTF. */
|
||||
/* kflag is 1 for structs/unions with a bitfield member.
|
||||
|
|
@ -810,16 +825,26 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
|
|||
structs and forwards to unions. The dwarf2ctf conversion process stores
|
||||
the kind of the forward in ctti_type, but for BTF this must be 0 for
|
||||
forwards, with only the KIND_FLAG to distinguish.
|
||||
At time of writing, BTF forwards to enums are unspecified. */
|
||||
if (btf_kind == BTF_KIND_FWD)
|
||||
Forwards to enum types are special-cased below. */
|
||||
else if (btf_kind == BTF_KIND_FWD)
|
||||
{
|
||||
if (dtd->dtd_data.ctti_type == CTF_K_UNION)
|
||||
btf_kflag = 1;
|
||||
|
||||
btf_size_type = 0;
|
||||
/* PR debug/111735. Encode foward-declared enums as BTF_KIND_ENUM
|
||||
with vlen=0. A representation for these is not formally defined;
|
||||
this is the de-facto standard used by other tools like clang
|
||||
and pahole. */
|
||||
else if (dtd->dtd_data.ctti_type == CTF_K_ENUM)
|
||||
{
|
||||
btf_kind = BTF_KIND_ENUM;
|
||||
btf_vlen = 0;
|
||||
}
|
||||
|
||||
btf_size = 0;
|
||||
}
|
||||
|
||||
if (btf_kind == BTF_KIND_ENUM)
|
||||
else if (btf_kind == BTF_KIND_ENUM)
|
||||
{
|
||||
btf_kflag = dtd->dtd_enum_unsigned
|
||||
? BTF_KF_ENUM_UNSIGNED
|
||||
|
|
@ -829,7 +854,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
|
|||
}
|
||||
|
||||
/* PR debug/112656. BTF_KIND_FUNC_PROTO is always anonymous. */
|
||||
if (btf_kind == BTF_KIND_FUNC_PROTO)
|
||||
else if (btf_kind == BTF_KIND_FUNC_PROTO)
|
||||
dtd->dtd_data.ctti_name = 0;
|
||||
|
||||
dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
|
||||
|
|
@ -848,8 +873,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
|
|||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_DATASEC:
|
||||
case BTF_KIND_ENUM64:
|
||||
dw2_asm_output_data (4, dtd->dtd_data.ctti_size, "btt_size: %uB",
|
||||
dtd->dtd_data.ctti_size);
|
||||
dw2_asm_output_data (4, btf_size, "btt_size: %uB", btf_size);
|
||||
return;
|
||||
case BTF_KIND_ARRAY:
|
||||
case BTF_KIND_FWD:
|
||||
|
|
|
|||
|
|
@ -1403,16 +1403,24 @@ get_memory_rtx (tree exp, tree len)
|
|||
|
||||
/* Built-in functions to perform an untyped call and return. */
|
||||
|
||||
#define set_apply_args_size(x) \
|
||||
(this_target_builtins->x_apply_args_size_plus_one = 1 + (x))
|
||||
#define get_apply_args_size() \
|
||||
(this_target_builtins->x_apply_args_size_plus_one - 1)
|
||||
/* Wrapper that implicitly applies a delta when getting or setting the
|
||||
enclosed value. */
|
||||
template <typename T>
|
||||
class delta_type
|
||||
{
|
||||
T &value; T const delta;
|
||||
public:
|
||||
delta_type (T &val, T dlt) : value (val), delta (dlt) {}
|
||||
operator T () const { return value + delta; }
|
||||
T operator = (T val) const { value = val - delta; return val; }
|
||||
};
|
||||
|
||||
#define saved_apply_args_size \
|
||||
(delta_type<int> (this_target_builtins->x_apply_args_size_plus_one, -1))
|
||||
#define apply_args_mode \
|
||||
(this_target_builtins->x_apply_args_mode)
|
||||
#define set_apply_result_size(x) \
|
||||
(this_target_builtins->x_apply_result_size_plus_one = 1 + (x))
|
||||
#define get_apply_result_size() \
|
||||
(this_target_builtins->x_apply_result_size_plus_one - 1)
|
||||
#define saved_apply_result_size \
|
||||
(delta_type<int> (this_target_builtins->x_apply_result_size_plus_one, -1))
|
||||
#define apply_result_mode \
|
||||
(this_target_builtins->x_apply_result_mode)
|
||||
|
||||
|
|
@ -1422,7 +1430,7 @@ get_memory_rtx (tree exp, tree len)
|
|||
static int
|
||||
apply_args_size (void)
|
||||
{
|
||||
int size = get_apply_args_size ();
|
||||
int size = saved_apply_args_size;
|
||||
int align;
|
||||
unsigned int regno;
|
||||
|
||||
|
|
@ -1456,7 +1464,7 @@ apply_args_size (void)
|
|||
else
|
||||
apply_args_mode[regno] = as_a <fixed_size_mode> (VOIDmode);
|
||||
|
||||
set_apply_args_size (size);
|
||||
saved_apply_args_size = size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
|
@ -1467,7 +1475,7 @@ apply_args_size (void)
|
|||
static int
|
||||
apply_result_size (void)
|
||||
{
|
||||
int size = get_apply_result_size ();
|
||||
int size = saved_apply_result_size;
|
||||
int align, regno;
|
||||
|
||||
/* The values computed by this function never change. */
|
||||
|
|
@ -1500,7 +1508,7 @@ apply_result_size (void)
|
|||
size = APPLY_RESULT_SIZE;
|
||||
#endif
|
||||
|
||||
set_apply_result_size (size);
|
||||
saved_apply_result_size = size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
|
@ -4483,10 +4491,6 @@ try_store_by_multiple_pieces (rtx to, rtx len, unsigned int ctz_len,
|
|||
if (max_len >> max_bits > min_len >> max_bits)
|
||||
tst_bits = max_bits;
|
||||
}
|
||||
/* ??? Do we have to check that all powers of two lengths from
|
||||
max_bits down to ctz_len pass can_store_by_pieces? As in, could
|
||||
it possibly be that xlenest passes while smaller power-of-two
|
||||
sizes don't? */
|
||||
|
||||
by_pieces_constfn constfun;
|
||||
void *constfundata;
|
||||
|
|
@ -5443,8 +5447,38 @@ expand_builtin_frame_address (tree fndecl, tree exp)
|
|||
static rtx
|
||||
expand_builtin_stack_address ()
|
||||
{
|
||||
return convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
|
||||
STACK_UNSIGNED);
|
||||
rtx ret = convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
|
||||
STACK_UNSIGNED);
|
||||
|
||||
/* Unbias the stack pointer, bringing it to the boundary between the
|
||||
stack area claimed by the active function calling this builtin,
|
||||
and stack ranges that could get clobbered if it called another
|
||||
function. It should NOT encompass any stack red zone, that is
|
||||
used in leaf functions.
|
||||
|
||||
On SPARC, the register save area is *not* considered active or
|
||||
used by the active function, but rather as akin to the area in
|
||||
which call-preserved registers are saved by callees. This
|
||||
enables __strub_leave to clear what would otherwise overlap with
|
||||
its own register save area.
|
||||
|
||||
If the address is computed too high or too low, parts of a stack
|
||||
range that should be scrubbed may be left unscrubbed, scrubbing
|
||||
may corrupt active portions of the stack frame, and stack ranges
|
||||
may be doubly-scrubbed by caller and callee.
|
||||
|
||||
In order for it to be just right, the area delimited by
|
||||
@code{__builtin_stack_address} and @code{__builtin_frame_address
|
||||
(0)} should encompass caller's registers saved by the function,
|
||||
local on-stack variables and @code{alloca} stack areas.
|
||||
Accumulated outgoing on-stack arguments, preallocated as part of
|
||||
a function's own prologue, are to be regarded as part of the
|
||||
(caller) function's active area as well, whereas those pushed or
|
||||
allocated temporarily for a call are regarded as part of the
|
||||
callee's stack range, rather than the caller's. */
|
||||
ret = plus_constant (ptr_mode, ret, STACK_POINTER_OFFSET);
|
||||
|
||||
return force_reg (ptr_mode, ret);
|
||||
}
|
||||
|
||||
/* Expand a call to builtin function __builtin_strub_enter. */
|
||||
|
|
|
|||
|
|
@ -1,3 +1,48 @@
|
|||
2023-12-21 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* c.opt (Walloc-size): Enable also for C++ and ObjC++.
|
||||
|
||||
2023-12-21 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR sanitizer/113092
|
||||
* c-ubsan.cc (ubsan_instrument_shift): Workaround for missing
|
||||
ubsan _BitInt support for the shift count.
|
||||
|
||||
2023-12-20 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
PR c/113050
|
||||
* c-common.cc (get_atomic_generic_size): Use
|
||||
OPT_Wdiscarded_qualifiers instead of
|
||||
OPT_Wincompatible_pointer_types.
|
||||
|
||||
2023-12-20 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* c.opt (Wcalloc-transposed-args): New warning.
|
||||
* c-common.h (warn_for_calloc, warn_for_alloc_size): Declare.
|
||||
* c-warn.cc (warn_for_calloc, warn_for_alloc_size): New functions.
|
||||
|
||||
2023-12-16 Andrew Carlotti <andrew.carlotti@arm.com>
|
||||
|
||||
* c-attribs.cc (attr_target_exclusions): Make
|
||||
target/target_clones exclusion target-dependent.
|
||||
(attr_target_clones_exclusions): Ditto, and add target_version.
|
||||
(attr_target_version_exclusions): New.
|
||||
(c_common_attribute_table): Add target_version.
|
||||
(handle_target_version_attribute): New.
|
||||
(handle_target_attribute): Amend comment.
|
||||
(handle_target_clones_attribute): Ditto.
|
||||
|
||||
2023-12-16 Andrew Carlotti <andrew.carlotti@arm.com>
|
||||
|
||||
* c-attribs.cc (attr_always_inline_exclusions): New.
|
||||
(attr_target_exclusions): Ditto.
|
||||
(attr_target_clones_exclusions): Ditto.
|
||||
(c_common_attribute_table): Add new exclusion lists.
|
||||
(handle_noinline_attribute): Remove custom exclusion handling.
|
||||
(handle_always_inline_attribute): Ditto.
|
||||
(handle_target_attribute): Ditto.
|
||||
(handle_target_clones_attribute): Ditto.
|
||||
|
||||
2023-12-13 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
* c.opt: Add -fdiagnostics-all-candidates.
|
||||
|
|
@ -14699,7 +14744,7 @@
|
|||
* c-common.c: Include gt-c-family-c-common.h.
|
||||
* c-pragma.c: Include gt-c-family-c-pragma.h.
|
||||
|
||||
Copyright (C) 2010-2023 Free Software Foundation, Inc.
|
||||
Copyright (C) 2010-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *);
|
|||
static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_assume_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_target_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_target_version_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree ignore_attribute (tree *, tree, tree, int, bool *);
|
||||
|
|
@ -217,6 +218,13 @@ static const struct attribute_spec::exclusions attr_inline_exclusions[] =
|
|||
ATTR_EXCL (NULL, false, false, false),
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
|
||||
{
|
||||
ATTR_EXCL ("noinline", true, true, true),
|
||||
ATTR_EXCL ("target_clones", true, true, true),
|
||||
ATTR_EXCL (NULL, false, false, false),
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
|
||||
{
|
||||
ATTR_EXCL ("always_inline", true, true, true),
|
||||
|
|
@ -224,6 +232,28 @@ static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
|
|||
ATTR_EXCL (NULL, false, false, false),
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_target_exclusions[] =
|
||||
{
|
||||
ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
|
||||
TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
|
||||
ATTR_EXCL (NULL, false, false, false),
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_target_clones_exclusions[] =
|
||||
{
|
||||
ATTR_EXCL ("always_inline", true, true, true),
|
||||
ATTR_EXCL ("target", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
|
||||
TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
|
||||
ATTR_EXCL ("target_version", true, true, true),
|
||||
ATTR_EXCL (NULL, false, false, false),
|
||||
};
|
||||
|
||||
static const struct attribute_spec::exclusions attr_target_version_exclusions[] =
|
||||
{
|
||||
ATTR_EXCL ("target_clones", true, true, true),
|
||||
ATTR_EXCL (NULL, false, false, false),
|
||||
};
|
||||
|
||||
extern const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
|
||||
{
|
||||
ATTR_EXCL ("alloc_align", true, true, true),
|
||||
|
|
@ -339,7 +369,7 @@ const struct attribute_spec c_common_gnu_attributes[] =
|
|||
handle_leaf_attribute, NULL },
|
||||
{ "always_inline", 0, 0, true, false, false, false,
|
||||
handle_always_inline_attribute,
|
||||
attr_inline_exclusions },
|
||||
attr_always_inline_exclusions },
|
||||
{ "gnu_inline", 0, 0, true, false, false, false,
|
||||
handle_gnu_inline_attribute,
|
||||
attr_inline_exclusions },
|
||||
|
|
@ -490,9 +520,14 @@ const struct attribute_spec c_common_gnu_attributes[] =
|
|||
{ "error", 1, 1, true, false, false, false,
|
||||
handle_error_attribute, NULL },
|
||||
{ "target", 1, -1, true, false, false, false,
|
||||
handle_target_attribute, NULL },
|
||||
handle_target_attribute,
|
||||
attr_target_exclusions },
|
||||
{ "target_version", 1, 1, true, false, false, false,
|
||||
handle_target_version_attribute,
|
||||
attr_target_version_exclusions },
|
||||
{ "target_clones", 1, -1, true, false, false, false,
|
||||
handle_target_clones_attribute, NULL },
|
||||
handle_target_clones_attribute,
|
||||
attr_target_clones_exclusions },
|
||||
{ "optimize", 1, -1, true, false, false, false,
|
||||
handle_optimize_attribute, NULL },
|
||||
/* For internal use only. The leading '*' both prevents its usage in
|
||||
|
|
@ -1580,16 +1615,7 @@ handle_noinline_attribute (tree *node, tree name,
|
|||
int ARG_UNUSED (flags), bool *no_add_attrs)
|
||||
{
|
||||
if (TREE_CODE (*node) == FUNCTION_DECL)
|
||||
{
|
||||
if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with attribute %qs", name, "always_inline");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else
|
||||
DECL_UNINLINABLE (*node) = 1;
|
||||
}
|
||||
DECL_UNINLINABLE (*node) = 1;
|
||||
else
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
|
|
@ -1671,22 +1697,9 @@ handle_always_inline_attribute (tree *node, tree name,
|
|||
{
|
||||
if (TREE_CODE (*node) == FUNCTION_DECL)
|
||||
{
|
||||
if (lookup_attribute ("noinline", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "noinline");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "target_clones");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else
|
||||
/* Set the attribute and mark it for disregarding inline
|
||||
limits. */
|
||||
DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
|
||||
/* Set the attribute and mark it for disregarding inline
|
||||
limits. */
|
||||
DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -5830,18 +5843,12 @@ static tree
|
|||
handle_target_attribute (tree *node, tree name, tree args, int flags,
|
||||
bool *no_add_attrs)
|
||||
{
|
||||
/* Ensure we have a function type. */
|
||||
/* Ensure we have a function declaration. */
|
||||
if (TREE_CODE (*node) != FUNCTION_DECL)
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "target_clones");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (! targetm.target_option.valid_attribute_p (*node, name, args,
|
||||
flags))
|
||||
*no_add_attrs = true;
|
||||
|
|
@ -5862,13 +5869,32 @@ handle_target_attribute (tree *node, tree name, tree args, int flags,
|
|||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "target_version" attribute. */
|
||||
|
||||
static tree
|
||||
handle_target_version_attribute (tree *node, tree name, tree args, int flags,
|
||||
bool *no_add_attrs)
|
||||
{
|
||||
/* Ensure we have a function declaration. */
|
||||
if (TREE_CODE (*node) != FUNCTION_DECL)
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (!targetm.target_option.valid_version_attribute_p (*node, name, args,
|
||||
flags))
|
||||
*no_add_attrs = true;
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "target_clones" attribute. */
|
||||
|
||||
static tree
|
||||
handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args),
|
||||
int ARG_UNUSED (flags), bool *no_add_attrs)
|
||||
{
|
||||
/* Ensure we have a function type. */
|
||||
/* Ensure we have a function declaration. */
|
||||
if (TREE_CODE (*node) == FUNCTION_DECL)
|
||||
{
|
||||
for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
|
||||
|
|
@ -5882,19 +5908,7 @@ handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args),
|
|||
}
|
||||
}
|
||||
|
||||
if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "always_inline");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (lookup_attribute ("target", DECL_ATTRIBUTES (*node)))
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
|
||||
"with %qs attribute", name, "target");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else if (get_target_clone_attr_len (args) == -1)
|
||||
if (get_target_clone_attr_len (args) == -1)
|
||||
{
|
||||
warning (OPT_Wattributes,
|
||||
"single %<target_clones%> attribute is ignored");
|
||||
|
|
|
|||
|
|
@ -7637,7 +7637,7 @@ get_atomic_generic_size (location_t loc, tree function,
|
|||
return 0;
|
||||
}
|
||||
else
|
||||
pedwarn (loc, OPT_Wincompatible_pointer_types, "argument %d "
|
||||
pedwarn (loc, OPT_Wdiscarded_qualifiers, "argument %d "
|
||||
"of %qE discards %<const%> qualifier", x + 1,
|
||||
function);
|
||||
}
|
||||
|
|
@ -7651,7 +7651,7 @@ get_atomic_generic_size (location_t loc, tree function,
|
|||
return 0;
|
||||
}
|
||||
else
|
||||
pedwarn (loc, OPT_Wincompatible_pointer_types, "argument %d "
|
||||
pedwarn (loc, OPT_Wdiscarded_qualifiers, "argument %d "
|
||||
"of %qE discards %<volatile%> qualifier", x + 1,
|
||||
function);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1599,6 +1599,9 @@ extern void warn_about_parentheses (location_t,
|
|||
extern void warn_for_unused_label (tree label);
|
||||
extern void warn_for_div_by_zero (location_t, tree divisor);
|
||||
extern void warn_for_memset (location_t, tree, tree, int);
|
||||
extern void warn_for_calloc (location_t *, tree, vec<tree, va_gc> *,
|
||||
tree *, tree);
|
||||
extern void warn_for_alloc_size (location_t, tree, tree, tree);
|
||||
extern void warn_for_sign_compare (location_t,
|
||||
tree orig_op0, tree orig_op1,
|
||||
tree op0, tree op1,
|
||||
|
|
|
|||
|
|
@ -256,6 +256,32 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
|
|||
tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
||||
else
|
||||
{
|
||||
if (TREE_CODE (type1) == BITINT_TYPE
|
||||
&& TYPE_PRECISION (type1) > MAX_FIXED_MODE_SIZE)
|
||||
{
|
||||
/* Workaround for missing _BitInt support in libsanitizer.
|
||||
Instead of crashing in the library, pretend values above
|
||||
maximum value of normal integral type or below minimum value
|
||||
of that type are those extremes. */
|
||||
tree type2 = build_nonstandard_integer_type (MAX_FIXED_MODE_SIZE,
|
||||
TYPE_UNSIGNED (type1));
|
||||
tree op2 = op1;
|
||||
if (!TYPE_UNSIGNED (type1))
|
||||
{
|
||||
op2 = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op1),
|
||||
fold_convert (type1, TYPE_MIN_VALUE (type2)));
|
||||
op2 = fold_build3 (COND_EXPR, type2, op2, TYPE_MIN_VALUE (type2),
|
||||
fold_convert (type2, unshare_expr (op1)));
|
||||
}
|
||||
else
|
||||
op2 = fold_convert (type2, op1);
|
||||
tree op3
|
||||
= fold_build2 (GT_EXPR, boolean_type_node, unshare_expr (op1),
|
||||
fold_convert (type1, TYPE_MAX_VALUE (type2)));
|
||||
op1 = fold_build3 (COND_EXPR, type2, op3, TYPE_MAX_VALUE (type2),
|
||||
op2);
|
||||
type1 = type2;
|
||||
}
|
||||
tree utd0 = ubsan_type_descriptor (type0, UBSAN_PRINT_FORCE_INT);
|
||||
tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc, utd0,
|
||||
ubsan_type_descriptor (type1), NULL_TREE,
|
||||
|
|
|
|||
|
|
@ -2263,6 +2263,76 @@ warn_for_memset (location_t loc, tree arg0, tree arg2,
|
|||
}
|
||||
}
|
||||
|
||||
/* Warn for calloc (sizeof (X), n). */
|
||||
|
||||
void
|
||||
warn_for_calloc (location_t *sizeof_arg_loc, tree callee,
|
||||
vec<tree, va_gc> *params, tree *sizeof_arg, tree attr)
|
||||
{
|
||||
if (!TREE_VALUE (attr) || !TREE_CHAIN (TREE_VALUE (attr)))
|
||||
return;
|
||||
|
||||
int arg1 = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))) - 1;
|
||||
int arg2
|
||||
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (TREE_VALUE (attr)))) - 1;
|
||||
if (arg1 < 0
|
||||
|| (unsigned) arg1 >= vec_safe_length (params)
|
||||
|| arg1 >= 6
|
||||
|| arg2 < 0
|
||||
|| (unsigned) arg2 >= vec_safe_length (params)
|
||||
|| arg2 >= 6
|
||||
|| arg1 >= arg2)
|
||||
return;
|
||||
|
||||
if (sizeof_arg[arg1] == NULL_TREE || sizeof_arg[arg2] != NULL_TREE)
|
||||
return;
|
||||
|
||||
if (warning_at (sizeof_arg_loc[arg1], OPT_Wcalloc_transposed_args,
|
||||
"%qD sizes specified with %<sizeof%> in the earlier "
|
||||
"argument and not in the later argument", callee))
|
||||
inform (sizeof_arg_loc[arg1], "earlier argument should specify number "
|
||||
"of elements, later size of each element");
|
||||
}
|
||||
|
||||
/* Warn for allocator calls where the constant allocated size is smaller
|
||||
than sizeof (TYPE). */
|
||||
|
||||
void
|
||||
warn_for_alloc_size (location_t loc, tree type, tree call, tree alloc_size)
|
||||
{
|
||||
if (!TREE_VALUE (alloc_size))
|
||||
return;
|
||||
|
||||
tree arg1 = TREE_VALUE (TREE_VALUE (alloc_size));
|
||||
int idx1 = TREE_INT_CST_LOW (arg1) - 1;
|
||||
if (idx1 < 0 || idx1 >= call_expr_nargs (call))
|
||||
return;
|
||||
arg1 = CALL_EXPR_ARG (call, idx1);
|
||||
if (TREE_CODE (arg1) != INTEGER_CST)
|
||||
return;
|
||||
if (TREE_CHAIN (TREE_VALUE (alloc_size)))
|
||||
{
|
||||
tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_VALUE (alloc_size)));
|
||||
int idx2 = TREE_INT_CST_LOW (arg2) - 1;
|
||||
if (idx2 < 0 || idx2 >= call_expr_nargs (call))
|
||||
return;
|
||||
arg2 = CALL_EXPR_ARG (call, idx2);
|
||||
if (TREE_CODE (arg2) != INTEGER_CST)
|
||||
return;
|
||||
arg1 = int_const_binop (MULT_EXPR, fold_convert (sizetype, arg1),
|
||||
fold_convert (sizetype, arg2));
|
||||
if (TREE_CODE (arg1) != INTEGER_CST)
|
||||
return;
|
||||
}
|
||||
if (!VOID_TYPE_P (type)
|
||||
&& TYPE_SIZE_UNIT (type)
|
||||
&& TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
|
||||
&& tree_int_cst_lt (arg1, TYPE_SIZE_UNIT (type)))
|
||||
warning_at (loc, OPT_Walloc_size,
|
||||
"allocation of insufficient size %qE for type %qT with "
|
||||
"size %qE", arg1, type, TYPE_SIZE_UNIT (type));
|
||||
}
|
||||
|
||||
/* Subroutine of build_binary_op. Give warnings for comparisons
|
||||
between signed and unsigned quantities that may fail. Do the
|
||||
checking based on the original operand trees ORIG_OP0 and ORIG_OP1,
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ C ObjC C++ ObjC++ Var(warn_alloca) Warning
|
|||
Warn on any use of alloca.
|
||||
|
||||
Walloc-size
|
||||
C ObjC Var(warn_alloc_size) Warning LangEnabledBy(C ObjC, Wextra)
|
||||
C ObjC C++ ObjC++ Var(warn_alloc_size) Warning LangEnabledBy(C ObjC C++ ObjC++, Wextra)
|
||||
Warn when allocating insufficient storage for the target type of the assigned pointer.
|
||||
|
||||
Walloc-size-larger-than=
|
||||
|
|
@ -502,6 +502,10 @@ Wc++26-extensions
|
|||
C++ ObjC++ Var(warn_cxx26_extensions) Warning Init(1)
|
||||
Warn about C++26 constructs in code compiled with an older standard.
|
||||
|
||||
Wcalloc-transposed-args
|
||||
C ObjC C++ ObjC++ Var(warn_calloc_transposed_args) Warning LangEnabledBy(C ObjC C++ ObjC++,Wextra)
|
||||
Warn about suspicious calls to calloc-like functions where sizeof expression is the earlier size argument and not the latter.
|
||||
|
||||
Wcast-function-type
|
||||
C ObjC C++ ObjC++ Var(warn_cast_function_type) Warning EnabledBy(Wextra)
|
||||
Warn about casts between incompatible function types.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,96 @@
|
|||
2023-12-30 Martin Uecker <uecker@tugraz.at>
|
||||
|
||||
* c-typeck.cc (tagged_types_tu_compatible_p): Revise.
|
||||
|
||||
2023-12-22 Martin Uecker <uecker@tugraz.at>
|
||||
|
||||
* c-typeck.cc (composite_type_internal): Adapted from
|
||||
composite_type to support structs and unions.
|
||||
(composite_type): New wrapper function.
|
||||
(build_conditional_operator): Return composite type.
|
||||
* c-decl.cc (finish_struct): Allow NULL for
|
||||
enclosing_struct_parse_info.
|
||||
|
||||
2023-12-21 Martin Uecker <uecker@tugraz.at>
|
||||
|
||||
* c-decl.cc (c_struct_hasher): Hash stable for struct
|
||||
types.
|
||||
(c_struct_hasher::hash, c_struct_hasher::equal): New
|
||||
functions.
|
||||
(finish_struct): Set TYPE_CANONICAL to first struct in
|
||||
equivalence class.
|
||||
* c-objc-common.cc (c_get_alias_set): Let structs or
|
||||
unions with variable size alias anything.
|
||||
* c-tree.h (comptypes_equiv): New prototype.
|
||||
* c-typeck.cc (comptypes_equiv): New function.
|
||||
(comptypes_internal): Implement equivalence mode.
|
||||
(tagged_types_tu_compatible): Implement equivalence mode.
|
||||
|
||||
2023-12-21 Martin Uecker <uecker@tugraz.at>
|
||||
|
||||
* c-tree.h (c_parser_enum_specifier): Add parameter.
|
||||
* c-decl.cc (start_enum): Allow redefinition.
|
||||
(finish_enum): Diagnose conflicts.
|
||||
(build_enumerator): Set context.
|
||||
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
|
||||
(push_decl): Preserve context for enumerators.
|
||||
* c-typeck.cc (tagged_types_tu_compatible_p): Adapt.
|
||||
* c-parser.cc (c_parser_enum_specifier): Remember when
|
||||
seen is from an enum type which is not yet defined.
|
||||
|
||||
2023-12-21 Martin Uecker <uecker@tugraz.at>
|
||||
|
||||
* c-decl.cc (previous_tag): New function.
|
||||
(parser_xref_tag): Find earlier definition.
|
||||
(get_parm_info): Turn off warning for C23.
|
||||
(start_struct): Allow redefinitons.
|
||||
(finish_struct): Diagnose conflicts.
|
||||
* c-tree.h (comptypes_same_p): Add prototype.
|
||||
* c-typeck.cc (comptypes_same_p): New function.
|
||||
(comptypes_internal): Activate comparison of tagged types.
|
||||
(convert_for_assignment): Ignore qualifiers.
|
||||
(digest_init): Add error.
|
||||
(initialized_elementwise_p): Allow compatible types.
|
||||
|
||||
2023-12-20 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* c-parser.cc (c_parser_postfix_expression_after_primary): Grow
|
||||
sizeof_arg and sizeof_arg_loc arrays to 6 elements. Call
|
||||
warn_for_calloc if warn_calloc_transposed_args for functions with
|
||||
alloc_size type attribute with 2 arguments.
|
||||
(c_parser_expr_list): Use 6 instead of 3.
|
||||
* c-typeck.cc (build_c_cast): Call warn_for_alloc_size for casts
|
||||
of calls to functions with alloc_size type attribute.
|
||||
(convert_for_assignment): Likewise.
|
||||
|
||||
2023-12-19 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* c-parser.cc (omp_construct_selectors): Delete.
|
||||
(omp_device_selectors): Delete.
|
||||
(omp_implementation_selectors): Delete.
|
||||
(omp_user_selectors): Delete.
|
||||
(c_parser_omp_context_selector): Adjust for new representations
|
||||
and simplify dispatch logic. Uniformly warn instead of sometimes
|
||||
error when an unknown selector is found. Adjust error messages
|
||||
for extraneous/incorrect score.
|
||||
(c_parser_omp_context_selector_specification): Likewise.
|
||||
(c_finish_omp_declare_variant): Adjust for new representations.
|
||||
|
||||
2023-12-19 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* c-parser.cc (c_parser_omp_context_selector): Adjust for new
|
||||
namelist property representation.
|
||||
|
||||
2023-12-19 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* c-parser.cc (c_parser_omp_context_selector): Use new constructors.
|
||||
|
||||
2023-12-18 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR c/111975
|
||||
* gimple-parser.cc (c_parser_gimple_postfix_expression):
|
||||
Parse TARGET_MEM_REF extended operands for __MEM.
|
||||
|
||||
2023-12-13 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* c-typeck.cc (convert_for_assignment): Adjust call to
|
||||
|
|
@ -9870,7 +9963,7 @@
|
|||
* c-decl.c: Likewise. Include gt-c-c-decl.h, not gt-c-decl.h.
|
||||
* c-parser.c: Likewise. Include gt-c-c-parser.h, not gt-c-parser.h.
|
||||
|
||||
Copyright (C) 2012-2023 Free Software Foundation, Inc.
|
||||
Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
|
|
|
|||
205
gcc/c/c-decl.cc
205
gcc/c/c-decl.cc
|
|
@ -634,6 +634,36 @@ public:
|
|||
auto_vec<tree> typedefs_seen;
|
||||
};
|
||||
|
||||
|
||||
/* Hash table for structs and unions. */
|
||||
struct c_struct_hasher : ggc_ptr_hash<tree_node>
|
||||
{
|
||||
static hashval_t hash (tree t);
|
||||
static bool equal (tree, tree);
|
||||
};
|
||||
|
||||
/* Hash an RECORD OR UNION. */
|
||||
hashval_t
|
||||
c_struct_hasher::hash (tree type)
|
||||
{
|
||||
inchash::hash hstate;
|
||||
|
||||
hstate.add_int (TREE_CODE (type));
|
||||
hstate.add_object (TYPE_NAME (type));
|
||||
|
||||
return hstate.end ();
|
||||
}
|
||||
|
||||
/* Compare two RECORD or UNION types. */
|
||||
bool
|
||||
c_struct_hasher::equal (tree t1, tree t2)
|
||||
{
|
||||
return comptypes_equiv_p (t1, t2);
|
||||
}
|
||||
|
||||
/* All tagged typed so that TYPE_CANONICAL can be set correctly. */
|
||||
static GTY (()) hash_table<c_struct_hasher> *c_struct_htab;
|
||||
|
||||
/* Information for the struct or union currently being parsed, or
|
||||
NULL if not parsing a struct or union. */
|
||||
static class c_struct_parse_info *struct_parse_info;
|
||||
|
|
@ -2037,6 +2067,28 @@ locate_old_decl (tree decl)
|
|||
decl, TREE_TYPE (decl));
|
||||
}
|
||||
|
||||
|
||||
/* Helper function. For a tagged type, it finds the declaration
|
||||
for a visible tag declared in the the same scope if such a
|
||||
declaration exists. */
|
||||
static tree
|
||||
previous_tag (tree type)
|
||||
{
|
||||
struct c_binding *b = NULL;
|
||||
tree name = TYPE_NAME (type);
|
||||
|
||||
if (name)
|
||||
b = I_TAG_BINDING (name);
|
||||
|
||||
if (b)
|
||||
b = b->shadowed;
|
||||
|
||||
if (b && B_IN_CURRENT_SCOPE (b))
|
||||
return b->decl;
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL.
|
||||
Returns true if the caller should proceed to merge the two, false
|
||||
if OLDDECL should simply be discarded. As a side effect, issues
|
||||
|
|
@ -2090,9 +2142,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
|
|||
given scope. */
|
||||
if (TREE_CODE (olddecl) == CONST_DECL)
|
||||
{
|
||||
auto_diagnostic_group d;
|
||||
error ("redeclaration of enumerator %q+D", newdecl);
|
||||
locate_old_decl (olddecl);
|
||||
if (flag_isoc23
|
||||
&& TYPE_NAME (DECL_CONTEXT (newdecl))
|
||||
&& DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
|
||||
&& TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT (olddecl)))
|
||||
{
|
||||
if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL (newdecl)))
|
||||
{
|
||||
auto_diagnostic_group d;
|
||||
error ("conflicting redeclaration of enumerator %q+D", newdecl);
|
||||
locate_old_decl (olddecl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto_diagnostic_group d;
|
||||
error ("redeclaration of enumerator %q+D", newdecl);
|
||||
locate_old_decl (olddecl);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3253,8 +3320,11 @@ pushdecl (tree x)
|
|||
|
||||
/* Must set DECL_CONTEXT for everything not at file scope or
|
||||
DECL_FILE_SCOPE_P won't work. Local externs don't count
|
||||
unless they have initializers (which generate code). */
|
||||
unless they have initializers (which generate code). We
|
||||
also exclude CONST_DECLs because enumerators will get the
|
||||
type of the enum as context. */
|
||||
if (current_function_decl
|
||||
&& TREE_CODE (x) != CONST_DECL
|
||||
&& (!VAR_OR_FUNCTION_DECL_P (x)
|
||||
|| DECL_INITIAL (x) || !TREE_PUBLIC (x)))
|
||||
DECL_CONTEXT (x) = current_function_decl;
|
||||
|
|
@ -8573,11 +8643,14 @@ get_parm_info (bool ellipsis, tree expr)
|
|||
if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
|
||||
{
|
||||
if (b->id)
|
||||
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
||||
warning_at (b->locus, 0,
|
||||
"%<%s %E%> declared inside parameter list"
|
||||
" will not be visible outside of this definition or"
|
||||
" declaration", keyword, b->id);
|
||||
{
|
||||
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
||||
if (!flag_isoc23)
|
||||
warning_at (b->locus, 0,
|
||||
"%<%s %E%> declared inside parameter list"
|
||||
" will not be visible outside of this definition or"
|
||||
" declaration", keyword, b->id);
|
||||
}
|
||||
else
|
||||
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
||||
warning_at (b->locus, 0,
|
||||
|
|
@ -8668,6 +8741,17 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name,
|
|||
present, only a definition in the current scope is relevant. */
|
||||
|
||||
ref = lookup_tag (code, name, has_enum_type_specifier, &refloc);
|
||||
|
||||
/* If the visble type is still being defined, see if there is
|
||||
an earlier definition (which may be complete). We do not
|
||||
have to loop because nested redefinitions are not allowed. */
|
||||
if (flag_isoc23 && ref && C_TYPE_BEING_DEFINED (ref))
|
||||
{
|
||||
tree vis = previous_tag (ref);
|
||||
if (vis)
|
||||
ref = vis;
|
||||
}
|
||||
|
||||
/* If this is the right type of tag, return what we found.
|
||||
(This reference will be shadowed by shadow_tag later if appropriate.)
|
||||
If this is the wrong type of tag, do not return it. If it was the
|
||||
|
|
@ -8782,6 +8866,14 @@ start_struct (location_t loc, enum tree_code code, tree name,
|
|||
|
||||
if (name != NULL_TREE)
|
||||
ref = lookup_tag (code, name, true, &refloc);
|
||||
|
||||
/* For C23, even if we already have a completed definition,
|
||||
we do not use it. We will check for consistency later.
|
||||
If we are in a nested redefinition the type is not
|
||||
complete. We will then detect this below. */
|
||||
if (flag_isoc23 && ref && TYPE_SIZE (ref))
|
||||
ref = NULL_TREE;
|
||||
|
||||
if (ref && TREE_CODE (ref) == code)
|
||||
{
|
||||
if (TYPE_STUB_DECL (ref))
|
||||
|
|
@ -9581,6 +9673,43 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
|
|||
warning_at (loc, 0, "union cannot be made transparent");
|
||||
}
|
||||
|
||||
/* Check for consistency with previous definition. */
|
||||
if (flag_isoc23 && NULL != enclosing_struct_parse_info)
|
||||
{
|
||||
tree vistype = previous_tag (t);
|
||||
if (vistype
|
||||
&& TREE_CODE (vistype) == TREE_CODE (t)
|
||||
&& !C_TYPE_BEING_DEFINED (vistype))
|
||||
{
|
||||
TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (t);
|
||||
if (c_type_variably_modified_p (t))
|
||||
error ("redefinition of struct or union %qT with variably "
|
||||
"modified type", t);
|
||||
else if (!comptypes_same_p (t, vistype))
|
||||
error ("redefinition of struct or union %qT", t);
|
||||
}
|
||||
}
|
||||
|
||||
C_TYPE_BEING_DEFINED (t) = 0;
|
||||
|
||||
/* Set type canonical based on equivalence class. */
|
||||
if (flag_isoc23)
|
||||
{
|
||||
if (NULL == c_struct_htab)
|
||||
c_struct_htab = hash_table<c_struct_hasher>::create_ggc (61);
|
||||
|
||||
hashval_t hash = c_struct_hasher::hash (t);
|
||||
|
||||
tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT);
|
||||
if (*e)
|
||||
TYPE_CANONICAL (t) = *e;
|
||||
else
|
||||
{
|
||||
TYPE_CANONICAL (t) = t;
|
||||
*e = t;
|
||||
}
|
||||
}
|
||||
|
||||
tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
|
||||
for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
|
||||
{
|
||||
|
|
@ -9615,16 +9744,19 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
|
|||
if (warn_cxx_compat)
|
||||
warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
|
||||
|
||||
delete struct_parse_info;
|
||||
if (NULL != enclosing_struct_parse_info)
|
||||
{
|
||||
delete struct_parse_info;
|
||||
|
||||
struct_parse_info = enclosing_struct_parse_info;
|
||||
struct_parse_info = enclosing_struct_parse_info;
|
||||
|
||||
/* If this struct is defined inside a struct, add it to
|
||||
struct_types. */
|
||||
if (warn_cxx_compat
|
||||
&& struct_parse_info != NULL
|
||||
&& !in_sizeof && !in_typeof && !in_alignof)
|
||||
struct_parse_info->struct_types.safe_push (t);
|
||||
/* If this struct is defined inside a struct, add it to
|
||||
struct_types. */
|
||||
if (warn_cxx_compat
|
||||
&& struct_parse_info != NULL
|
||||
&& !in_sizeof && !in_typeof && !in_alignof)
|
||||
struct_parse_info->struct_types.safe_push (t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
|
@ -9697,7 +9829,7 @@ layout_array_type (tree t)
|
|||
|
||||
tree
|
||||
start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
|
||||
tree fixed_underlying_type)
|
||||
tree fixed_underlying_type, bool potential_nesting_p)
|
||||
{
|
||||
tree enumtype = NULL_TREE;
|
||||
location_t enumloc = UNKNOWN_LOCATION;
|
||||
|
|
@ -9709,9 +9841,26 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
|
|||
if (name != NULL_TREE)
|
||||
enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
|
||||
|
||||
if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
|
||||
{
|
||||
/* If the type is currently being defined or if we have seen an
|
||||
incomplete version which is now complete, this is a nested
|
||||
redefinition. The later happens if the redefinition occurs
|
||||
inside the enum specifier itself. */
|
||||
if (C_TYPE_BEING_DEFINED (enumtype)
|
||||
|| (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
|
||||
error_at (loc, "nested redefinition of %<enum %E%>", name);
|
||||
|
||||
/* For C23 we allow redefinitions. We set to zero and check for
|
||||
consistency later. */
|
||||
if (flag_isoc23 && TYPE_VALUES (enumtype) != NULL_TREE)
|
||||
enumtype = NULL_TREE;
|
||||
}
|
||||
|
||||
if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
|
||||
{
|
||||
enumtype = make_node (ENUMERAL_TYPE);
|
||||
TYPE_SIZE (enumtype) = NULL_TREE;
|
||||
pushtag (loc, name, enumtype);
|
||||
if (fixed_underlying_type != NULL_TREE)
|
||||
{
|
||||
|
|
@ -9739,9 +9888,6 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
|
|||
DECL_SOURCE_LOCATION (TYPE_STUB_DECL (enumtype)) = loc;
|
||||
}
|
||||
|
||||
if (C_TYPE_BEING_DEFINED (enumtype))
|
||||
error_at (loc, "nested redefinition of %<enum %E%>", name);
|
||||
|
||||
C_TYPE_BEING_DEFINED (enumtype) = 1;
|
||||
|
||||
if (TYPE_VALUES (enumtype) != NULL_TREE)
|
||||
|
|
@ -9971,6 +10117,20 @@ finish_enum (tree enumtype, tree values, tree attributes)
|
|||
&& !in_sizeof && !in_typeof && !in_alignof)
|
||||
struct_parse_info->struct_types.safe_push (enumtype);
|
||||
|
||||
/* Check for consistency with previous definition */
|
||||
if (flag_isoc23)
|
||||
{
|
||||
tree vistype = previous_tag (enumtype);
|
||||
if (vistype
|
||||
&& TREE_CODE (vistype) == TREE_CODE (enumtype)
|
||||
&& !C_TYPE_BEING_DEFINED (vistype))
|
||||
{
|
||||
TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype);
|
||||
if (!comptypes_same_p (enumtype, vistype))
|
||||
error("conflicting redefinition of enum %qT", enumtype);
|
||||
}
|
||||
}
|
||||
|
||||
C_TYPE_BEING_DEFINED (enumtype) = 0;
|
||||
|
||||
return enumtype;
|
||||
|
|
@ -10150,6 +10310,7 @@ build_enumerator (location_t decl_loc, location_t loc,
|
|||
|
||||
decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value));
|
||||
DECL_INITIAL (decl) = value;
|
||||
DECL_CONTEXT (decl) = the_enum->enum_type;
|
||||
pushdecl (decl);
|
||||
|
||||
return tree_cons (decl, value, NULL_TREE);
|
||||
|
|
@ -10166,7 +10327,7 @@ c_simulate_enum_decl (location_t loc, const char *name,
|
|||
|
||||
struct c_enum_contents the_enum;
|
||||
tree enumtype = start_enum (loc, &the_enum, get_identifier (name),
|
||||
NULL_TREE);
|
||||
NULL_TREE, false);
|
||||
|
||||
tree value_chain = NULL_TREE;
|
||||
string_int_pair *value;
|
||||
|
|
|
|||
|
|
@ -422,6 +422,11 @@ c_get_alias_set (tree t)
|
|||
if (TREE_CODE (t) == ENUMERAL_TYPE)
|
||||
return get_alias_set (ENUM_UNDERLYING_TYPE (t));
|
||||
|
||||
/* Structs with variable size can alias different incompatible
|
||||
structs. Let them alias anything. */
|
||||
if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t))
|
||||
return 0;
|
||||
|
||||
return c_common_get_alias_set (t);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3667,6 +3667,7 @@ c_parser_enum_specifier (c_parser *parser)
|
|||
{
|
||||
struct c_typespec ret;
|
||||
bool have_std_attrs;
|
||||
bool potential_nesting_p = false;
|
||||
tree std_attrs = NULL_TREE;
|
||||
tree attrs;
|
||||
tree ident = NULL_TREE;
|
||||
|
|
@ -3706,6 +3707,7 @@ c_parser_enum_specifier (c_parser *parser)
|
|||
if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec))
|
||||
error_at (enum_loc, "%<enum%> declared both with and without "
|
||||
"fixed underlying type");
|
||||
potential_nesting_p = NULL_TREE == TYPE_VALUES (ret.spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3776,7 +3778,8 @@ c_parser_enum_specifier (c_parser *parser)
|
|||
forward order at the end. */
|
||||
tree values;
|
||||
timevar_push (TV_PARSE_ENUM);
|
||||
type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type);
|
||||
type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type,
|
||||
potential_nesting_p);
|
||||
values = NULL_TREE;
|
||||
c_parser_consume_token (parser);
|
||||
while (true)
|
||||
|
|
@ -12478,8 +12481,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
|
|||
{
|
||||
struct c_expr orig_expr;
|
||||
tree ident, idx;
|
||||
location_t sizeof_arg_loc[3], comp_loc;
|
||||
tree sizeof_arg[3];
|
||||
location_t sizeof_arg_loc[6], comp_loc;
|
||||
tree sizeof_arg[6];
|
||||
unsigned int literal_zero_mask;
|
||||
unsigned int i;
|
||||
vec<tree, va_gc> *exprlist;
|
||||
|
|
@ -12512,7 +12515,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
|
|||
{
|
||||
matching_parens parens;
|
||||
parens.consume_open (parser);
|
||||
for (i = 0; i < 3; i++)
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
sizeof_arg[i] = NULL_TREE;
|
||||
sizeof_arg_loc[i] = UNKNOWN_LOCATION;
|
||||
|
|
@ -12577,6 +12580,13 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
|
|||
"not permitted in intervening code");
|
||||
parser->omp_for_parse_state->fail = true;
|
||||
}
|
||||
if (warn_calloc_transposed_args)
|
||||
if (tree attr = lookup_attribute ("alloc_size",
|
||||
TYPE_ATTRIBUTES
|
||||
(TREE_TYPE (expr.value))))
|
||||
if (TREE_VALUE (attr) && TREE_CHAIN (TREE_VALUE (attr)))
|
||||
warn_for_calloc (sizeof_arg_loc, expr.value, exprlist,
|
||||
sizeof_arg, attr);
|
||||
}
|
||||
|
||||
start = expr.get_start ();
|
||||
|
|
@ -12861,7 +12871,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
|
|||
vec_safe_push (orig_types, expr.original_type);
|
||||
if (locations)
|
||||
locations->safe_push (expr.get_location ());
|
||||
if (++idx < 3
|
||||
if (++idx < 6
|
||||
&& sizeof_arg != NULL
|
||||
&& (expr.original_code == SIZEOF_EXPR
|
||||
|| expr.original_code == PAREN_SIZEOF_EXPR))
|
||||
|
|
@ -24370,26 +24380,20 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *const omp_construct_selectors[] = {
|
||||
"simd", "target", "teams", "parallel", "for", NULL };
|
||||
static const char *const omp_device_selectors[] = {
|
||||
"kind", "isa", "arch", NULL };
|
||||
static const char *const omp_implementation_selectors[] = {
|
||||
"vendor", "extension", "atomic_default_mem_order", "unified_address",
|
||||
"unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
|
||||
static const char *const omp_user_selectors[] = {
|
||||
"condition", NULL };
|
||||
|
||||
/* OpenMP 5.0:
|
||||
|
||||
trait-selector:
|
||||
trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])]
|
||||
|
||||
trait-score:
|
||||
score(score-expression) */
|
||||
score(score-expression)
|
||||
|
||||
Note that this function returns a list of trait selectors for the
|
||||
trait-selector-set SET. */
|
||||
|
||||
static tree
|
||||
c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
||||
c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set,
|
||||
tree parms)
|
||||
{
|
||||
tree ret = NULL_TREE;
|
||||
do
|
||||
|
|
@ -24403,79 +24407,41 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
c_parser_error (parser, "expected trait selector name");
|
||||
return error_mark_node;
|
||||
}
|
||||
enum omp_ts_code sel
|
||||
= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
|
||||
|
||||
tree properties = NULL_TREE;
|
||||
const char *const *selectors = NULL;
|
||||
bool allow_score = true;
|
||||
bool allow_user = false;
|
||||
int property_limit = 0;
|
||||
enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
|
||||
CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
|
||||
CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
|
||||
switch (IDENTIFIER_POINTER (set)[0])
|
||||
if (sel == OMP_TRAIT_INVALID)
|
||||
{
|
||||
case 'c': /* construct */
|
||||
selectors = omp_construct_selectors;
|
||||
allow_score = false;
|
||||
property_limit = 1;
|
||||
property_kind = CTX_PROPERTY_SIMD;
|
||||
break;
|
||||
case 'd': /* device */
|
||||
selectors = omp_device_selectors;
|
||||
allow_score = false;
|
||||
allow_user = true;
|
||||
property_limit = 3;
|
||||
property_kind = CTX_PROPERTY_NAME_LIST;
|
||||
break;
|
||||
case 'i': /* implementation */
|
||||
selectors = omp_implementation_selectors;
|
||||
allow_user = true;
|
||||
property_limit = 3;
|
||||
property_kind = CTX_PROPERTY_NAME_LIST;
|
||||
break;
|
||||
case 'u': /* user */
|
||||
selectors = omp_user_selectors;
|
||||
property_limit = 1;
|
||||
property_kind = CTX_PROPERTY_EXPR;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
if (selectors[i] == NULL)
|
||||
/* Per the spec, "Implementations can ignore specified selectors
|
||||
that are not those described in this section"; however, we
|
||||
must record such selectors because they cause match failures. */
|
||||
warning_at (c_parser_peek_token (parser)->location, OPT_Wopenmp,
|
||||
"unknown selector %qs for context selector set %qs",
|
||||
IDENTIFIER_POINTER (selector), omp_tss_map[set]);
|
||||
c_parser_consume_token (parser);
|
||||
ret = make_trait_selector (sel, NULL_TREE, NULL_TREE, ret);
|
||||
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
|
||||
c_parser_balanced_token_sequence (parser);
|
||||
if (c_parser_next_token_is (parser, CPP_COMMA))
|
||||
{
|
||||
if (allow_user)
|
||||
{
|
||||
property_kind = CTX_PROPERTY_USER;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at (c_parser_peek_token (parser)->location,
|
||||
"selector %qs not allowed for context selector "
|
||||
"set %qs", IDENTIFIER_POINTER (selector),
|
||||
IDENTIFIER_POINTER (set));
|
||||
c_parser_consume_token (parser);
|
||||
return error_mark_node;
|
||||
}
|
||||
c_parser_consume_token (parser);
|
||||
continue;
|
||||
}
|
||||
if (i == property_limit)
|
||||
property_kind = CTX_PROPERTY_NONE;
|
||||
if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (property_kind == CTX_PROPERTY_NAME_LIST
|
||||
&& IDENTIFIER_POINTER (set)[0] == 'i'
|
||||
&& strcmp (IDENTIFIER_POINTER (selector),
|
||||
"atomic_default_mem_order") == 0)
|
||||
property_kind = CTX_PROPERTY_ID;
|
||||
|
||||
c_parser_consume_token (parser);
|
||||
|
||||
tree properties = NULL_TREE;
|
||||
tree scoreval = NULL_TREE;
|
||||
enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
|
||||
bool allow_score = omp_ts_map[sel].allow_score;
|
||||
tree t;
|
||||
|
||||
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
|
||||
{
|
||||
if (property_kind == CTX_PROPERTY_NONE)
|
||||
if (property_kind == OMP_TRAIT_PROPERTY_NONE)
|
||||
{
|
||||
error_at (c_parser_peek_token (parser)->location,
|
||||
"selector %qs does not accept any properties",
|
||||
|
|
@ -24487,8 +24453,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
parens.require_open (parser);
|
||||
|
||||
c_token *token = c_parser_peek_token (parser);
|
||||
if (allow_score
|
||||
&& c_parser_next_token_is (parser, CPP_NAME)
|
||||
if (c_parser_next_token_is (parser, CPP_NAME)
|
||||
&& strcmp (IDENTIFIER_POINTER (token->value), "score") == 0
|
||||
&& c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
|
||||
{
|
||||
|
|
@ -24499,62 +24464,38 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
tree score = c_parser_expr_no_commas (parser, NULL).value;
|
||||
parens2.skip_until_found_close (parser);
|
||||
c_parser_require (parser, CPP_COLON, "expected %<:%>");
|
||||
if (score != error_mark_node)
|
||||
if (!allow_score)
|
||||
error_at (token->location,
|
||||
"%<score%> cannot be specified in traits "
|
||||
"in the %qs trait-selector-set",
|
||||
omp_tss_map[set]);
|
||||
else if (score != error_mark_node)
|
||||
{
|
||||
mark_exp_read (score);
|
||||
score = c_fully_fold (score, false, NULL);
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (score))
|
||||
|| TREE_CODE (score) != INTEGER_CST)
|
||||
error_at (token->location, "score argument must be "
|
||||
"constant integer expression");
|
||||
error_at (token->location, "%<score%> argument must "
|
||||
"be constant integer expression");
|
||||
else if (tree_int_cst_sgn (score) < 0)
|
||||
error_at (token->location, "score argument must be "
|
||||
"non-negative");
|
||||
error_at (token->location, "%<score%> argument must "
|
||||
"be non-negative");
|
||||
else
|
||||
properties = tree_cons (get_identifier (" score"),
|
||||
score, properties);
|
||||
scoreval = score;
|
||||
}
|
||||
token = c_parser_peek_token (parser);
|
||||
}
|
||||
|
||||
switch (property_kind)
|
||||
{
|
||||
tree t;
|
||||
case CTX_PROPERTY_USER:
|
||||
do
|
||||
{
|
||||
t = c_parser_expr_no_commas (parser, NULL).value;
|
||||
if (TREE_CODE (t) == STRING_CST)
|
||||
properties = tree_cons (NULL_TREE, t, properties);
|
||||
else if (t != error_mark_node)
|
||||
{
|
||||
mark_exp_read (t);
|
||||
t = c_fully_fold (t, false, NULL);
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
|
||||
|| !tree_fits_shwi_p (t))
|
||||
error_at (token->location, "property must be "
|
||||
"constant integer expression or string "
|
||||
"literal");
|
||||
else
|
||||
properties = tree_cons (NULL_TREE, t, properties);
|
||||
}
|
||||
else
|
||||
return error_mark_node;
|
||||
|
||||
if (c_parser_next_token_is (parser, CPP_COMMA))
|
||||
c_parser_consume_token (parser);
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
break;
|
||||
case CTX_PROPERTY_ID:
|
||||
case OMP_TRAIT_PROPERTY_ID:
|
||||
if (c_parser_next_token_is (parser, CPP_KEYWORD)
|
||||
|| c_parser_next_token_is (parser, CPP_NAME))
|
||||
{
|
||||
tree prop = c_parser_peek_token (parser)->value;
|
||||
c_parser_consume_token (parser);
|
||||
properties = tree_cons (prop, NULL_TREE, properties);
|
||||
properties = make_trait_property (prop, NULL_TREE,
|
||||
properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -24562,14 +24503,15 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
return error_mark_node;
|
||||
}
|
||||
break;
|
||||
case CTX_PROPERTY_NAME_LIST:
|
||||
case OMP_TRAIT_PROPERTY_NAME_LIST:
|
||||
do
|
||||
{
|
||||
tree prop = NULL_TREE, value = NULL_TREE;
|
||||
tree prop = OMP_TP_NAMELIST_NODE;
|
||||
tree value = NULL_TREE;
|
||||
if (c_parser_next_token_is (parser, CPP_KEYWORD)
|
||||
|| c_parser_next_token_is (parser, CPP_NAME))
|
||||
{
|
||||
prop = c_parser_peek_token (parser)->value;
|
||||
value = c_parser_peek_token (parser)->value;
|
||||
c_parser_consume_token (parser);
|
||||
}
|
||||
else if (c_parser_next_token_is (parser, CPP_STRING))
|
||||
|
|
@ -24582,7 +24524,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
return error_mark_node;
|
||||
}
|
||||
|
||||
properties = tree_cons (prop, value, properties);
|
||||
properties = make_trait_property (prop, value, properties);
|
||||
|
||||
if (c_parser_next_token_is (parser, CPP_COMMA))
|
||||
c_parser_consume_token (parser);
|
||||
|
|
@ -24591,39 +24533,56 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
}
|
||||
while (1);
|
||||
break;
|
||||
case CTX_PROPERTY_EXPR:
|
||||
case OMP_TRAIT_PROPERTY_EXPR:
|
||||
t = c_parser_expr_no_commas (parser, NULL).value;
|
||||
if (t != error_mark_node)
|
||||
{
|
||||
mark_exp_read (t);
|
||||
t = c_fully_fold (t, false, NULL);
|
||||
/* FIXME: this is bogus, both device_num and
|
||||
condition selectors allow arbitrary expressions. */
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
|
||||
|| !tree_fits_shwi_p (t))
|
||||
error_at (token->location, "property must be "
|
||||
"constant integer expression");
|
||||
else
|
||||
properties = tree_cons (NULL_TREE, t, properties);
|
||||
properties = make_trait_property (NULL_TREE, t,
|
||||
properties);
|
||||
}
|
||||
else
|
||||
return error_mark_node;
|
||||
break;
|
||||
case CTX_PROPERTY_SIMD:
|
||||
if (parms == NULL_TREE)
|
||||
case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
|
||||
if (sel == OMP_TRAIT_CONSTRUCT_SIMD)
|
||||
{
|
||||
error_at (token->location, "properties for %<simd%> "
|
||||
"selector may not be specified in "
|
||||
"%<metadirective%>");
|
||||
if (parms == NULL_TREE)
|
||||
{
|
||||
error_at (token->location, "properties for %<simd%> "
|
||||
"selector may not be specified in "
|
||||
"%<metadirective%>");
|
||||
return error_mark_node;
|
||||
}
|
||||
tree c;
|
||||
c = c_parser_omp_all_clauses (parser,
|
||||
OMP_DECLARE_SIMD_CLAUSE_MASK,
|
||||
"simd", true, 2);
|
||||
c = c_omp_declare_simd_clauses_to_numbers (parms
|
||||
== error_mark_node
|
||||
? NULL_TREE : parms,
|
||||
c);
|
||||
properties = c;
|
||||
}
|
||||
else if (sel == OMP_TRAIT_IMPLEMENTATION_REQUIRES)
|
||||
{
|
||||
/* FIXME: The "requires" selector was added in OpenMP 5.1.
|
||||
Currently only the now-deprecated syntax
|
||||
from OpenMP 5.0 is supported. */
|
||||
sorry_at (token->location,
|
||||
"%<requires%> selector is not supported yet");
|
||||
return error_mark_node;
|
||||
}
|
||||
tree c;
|
||||
c = c_parser_omp_all_clauses (parser,
|
||||
OMP_DECLARE_SIMD_CLAUSE_MASK,
|
||||
"simd", true, 2);
|
||||
c = c_omp_declare_simd_clauses_to_numbers (parms
|
||||
== error_mark_node
|
||||
? NULL_TREE : parms,
|
||||
c);
|
||||
properties = c;
|
||||
else
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
|
|
@ -24632,15 +24591,15 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
|
|||
parens.skip_until_found_close (parser);
|
||||
properties = nreverse (properties);
|
||||
}
|
||||
else if (property_kind == CTX_PROPERTY_NAME_LIST
|
||||
|| property_kind == CTX_PROPERTY_ID
|
||||
|| property_kind == CTX_PROPERTY_EXPR)
|
||||
else if (property_kind != OMP_TRAIT_PROPERTY_NONE
|
||||
&& property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
|
||||
&& property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
|
||||
{
|
||||
c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
ret = tree_cons (selector, properties, ret);
|
||||
ret = make_trait_selector (sel, scoreval, properties, ret);
|
||||
|
||||
if (c_parser_next_token_is (parser, CPP_COMMA))
|
||||
c_parser_consume_token (parser);
|
||||
|
|
@ -24674,35 +24633,14 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
|
|||
const char *setp = "";
|
||||
if (c_parser_next_token_is (parser, CPP_NAME))
|
||||
setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
|
||||
switch (setp[0])
|
||||
enum omp_tss_code set = omp_lookup_tss_code (setp);
|
||||
|
||||
if (set == OMP_TRAIT_SET_INVALID)
|
||||
{
|
||||
case 'c':
|
||||
if (strcmp (setp, "construct") == 0)
|
||||
setp = NULL;
|
||||
break;
|
||||
case 'd':
|
||||
if (strcmp (setp, "device") == 0)
|
||||
setp = NULL;
|
||||
break;
|
||||
case 'i':
|
||||
if (strcmp (setp, "implementation") == 0)
|
||||
setp = NULL;
|
||||
break;
|
||||
case 'u':
|
||||
if (strcmp (setp, "user") == 0)
|
||||
setp = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (setp)
|
||||
{
|
||||
c_parser_error (parser, "expected %<construct%>, %<device%>, "
|
||||
"%<implementation%> or %<user%>");
|
||||
c_parser_error (parser, "expected context selector set name");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
tree set = c_parser_peek_token (parser)->value;
|
||||
c_parser_consume_token (parser);
|
||||
|
||||
if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
|
||||
|
|
@ -24716,7 +24654,7 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
|
|||
if (selectors == error_mark_node)
|
||||
ret = error_mark_node;
|
||||
else if (ret != error_mark_node)
|
||||
ret = tree_cons (set, selectors, ret);
|
||||
ret = make_trait_set_selector (set, selectors, ret);
|
||||
|
||||
braces.skip_until_found_close (parser);
|
||||
|
||||
|
|
@ -24799,7 +24737,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
|
|||
error_at (token->location, "variant %qD is not a function", variant);
|
||||
variant = error_mark_node;
|
||||
}
|
||||
else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE
|
||||
else if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
|
||||
OMP_TRAIT_CONSTRUCT_SIMD)
|
||||
&& !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
|
||||
{
|
||||
error_at (token->location, "variant %qD and base %qD have "
|
||||
|
|
@ -24820,7 +24759,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
|
|||
if (variant != error_mark_node)
|
||||
{
|
||||
C_DECL_USED (variant) = 1;
|
||||
tree construct = omp_get_context_selector (ctx, "construct", NULL);
|
||||
tree construct
|
||||
= omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
|
||||
omp_mark_declare_variant (match_loc, variant, construct);
|
||||
if (omp_context_selector_matches (ctx))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -683,7 +683,8 @@ extern void c_warn_unused_attributes (tree);
|
|||
extern tree c_warn_type_attributes (tree);
|
||||
extern void shadow_tag (const struct c_declspecs *);
|
||||
extern void shadow_tag_warned (const struct c_declspecs *, int);
|
||||
extern tree start_enum (location_t, struct c_enum_contents *, tree, tree);
|
||||
extern tree start_enum (location_t, struct c_enum_contents *, tree, tree,
|
||||
bool potential_nesting_p);
|
||||
extern bool start_function (struct c_declspecs *, struct c_declarator *, tree);
|
||||
extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool,
|
||||
tree, bool = true, location_t * = NULL);
|
||||
|
|
@ -757,6 +758,8 @@ extern tree c_objc_common_truthvalue_conversion (location_t, tree);
|
|||
extern tree require_complete_type (location_t, tree);
|
||||
extern bool same_translation_unit_p (const_tree, const_tree);
|
||||
extern int comptypes (tree, tree);
|
||||
extern bool comptypes_same_p (tree, tree);
|
||||
extern bool comptypes_equiv_p (tree, tree);
|
||||
extern int comptypes_check_different_types (tree, tree, bool *);
|
||||
extern int comptypes_check_enum_int (tree, tree, bool *);
|
||||
extern bool c_mark_addressable (tree, bool = false);
|
||||
|
|
|
|||
|
|
@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, tree attrs)
|
|||
nonzero; if that isn't so, this may crash. In particular, we
|
||||
assume that qualifiers match. */
|
||||
|
||||
struct composite_cache {
|
||||
tree t1;
|
||||
tree t2;
|
||||
tree composite;
|
||||
struct composite_cache* next;
|
||||
};
|
||||
|
||||
tree
|
||||
composite_type (tree t1, tree t2)
|
||||
composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
|
||||
{
|
||||
enum tree_code code1;
|
||||
enum tree_code code2;
|
||||
|
|
@ -427,7 +434,8 @@ composite_type (tree t1, tree t2)
|
|||
{
|
||||
tree pointed_to_1 = TREE_TYPE (t1);
|
||||
tree pointed_to_2 = TREE_TYPE (t2);
|
||||
tree target = composite_type (pointed_to_1, pointed_to_2);
|
||||
tree target = composite_type_internal (pointed_to_1,
|
||||
pointed_to_2, cache);
|
||||
t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
|
||||
t1 = build_type_attribute_variant (t1, attributes);
|
||||
return qualify_type (t1, t2);
|
||||
|
|
@ -435,7 +443,8 @@ composite_type (tree t1, tree t2)
|
|||
|
||||
case ARRAY_TYPE:
|
||||
{
|
||||
tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
|
||||
tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2),
|
||||
cache);
|
||||
int quals;
|
||||
tree unqual_elt;
|
||||
tree d1 = TYPE_DOMAIN (t1);
|
||||
|
|
@ -503,9 +512,87 @@ composite_type (tree t1, tree t2)
|
|||
return build_type_attribute_variant (t1, attributes);
|
||||
}
|
||||
|
||||
case ENUMERAL_TYPE:
|
||||
case RECORD_TYPE:
|
||||
case UNION_TYPE:
|
||||
if (flag_isoc23 && !comptypes_same_p (t1, t2))
|
||||
{
|
||||
gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
|
||||
gcc_checking_assert (!TYPE_NAME (t1) || comptypes (t1, t2));
|
||||
|
||||
/* If a composite type for these two types is already under
|
||||
construction, return it. */
|
||||
|
||||
for (struct composite_cache *c = cache; c != NULL; c = c->next)
|
||||
if (c->t1 == t1 && c->t2 == t2)
|
||||
return c->composite;
|
||||
|
||||
/* Otherwise, create a new type node and link it into the cache. */
|
||||
|
||||
tree n = make_node (code1);
|
||||
TYPE_NAME (n) = TYPE_NAME (t1);
|
||||
|
||||
struct composite_cache cache2 = { t1, t2, n, cache };
|
||||
cache = &cache2;
|
||||
|
||||
tree f1 = TYPE_FIELDS (t1);
|
||||
tree f2 = TYPE_FIELDS (t2);
|
||||
tree fields = NULL_TREE;
|
||||
|
||||
for (tree a = f1, b = f2; a && b;
|
||||
a = DECL_CHAIN (a), b = DECL_CHAIN (b))
|
||||
{
|
||||
tree ta = TREE_TYPE (a);
|
||||
tree tb = TREE_TYPE (b);
|
||||
|
||||
if (DECL_C_BIT_FIELD (a))
|
||||
{
|
||||
ta = DECL_BIT_FIELD_TYPE (a);
|
||||
tb = DECL_BIT_FIELD_TYPE (b);
|
||||
}
|
||||
|
||||
gcc_assert (DECL_NAME (a) == DECL_NAME (b));
|
||||
gcc_checking_assert (!DECL_NAME (a) || comptypes (ta, tb));
|
||||
|
||||
tree t = composite_type_internal (ta, tb, cache);
|
||||
tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a), t);
|
||||
|
||||
DECL_PACKED (f) = DECL_PACKED (a);
|
||||
SET_DECL_ALIGN (f, DECL_ALIGN (a));
|
||||
DECL_ATTRIBUTES (f) = DECL_ATTRIBUTES (a);
|
||||
C_DECL_VARIABLE_SIZE (f) = C_TYPE_VARIABLE_SIZE (t);
|
||||
|
||||
finish_decl (f, input_location, NULL, NULL, NULL);
|
||||
|
||||
if (DECL_C_BIT_FIELD (a))
|
||||
{
|
||||
/* This will be processed by finish_struct. */
|
||||
SET_DECL_C_BIT_FIELD (f);
|
||||
DECL_INITIAL (f) = build_int_cst (integer_type_node,
|
||||
tree_to_uhwi (DECL_SIZE (a)));
|
||||
DECL_NONADDRESSABLE_P (f) = true;
|
||||
DECL_PADDING_P (f) = !DECL_NAME (a);
|
||||
}
|
||||
|
||||
DECL_CHAIN (f) = fields;
|
||||
fields = f;
|
||||
}
|
||||
|
||||
fields = nreverse (fields);
|
||||
|
||||
/* Setup the struct/union type. Because we inherit all variably
|
||||
modified components, we can ignore the size expression. */
|
||||
tree expr = NULL_TREE;
|
||||
n = finish_struct(input_location, n, fields, attributes, NULL, &expr);
|
||||
|
||||
n = qualify_type (n, t1);
|
||||
|
||||
gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t1));
|
||||
gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t2));
|
||||
|
||||
return n;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case ENUMERAL_TYPE:
|
||||
if (attributes != NULL)
|
||||
{
|
||||
/* Try harder not to create a new aggregate type. */
|
||||
|
|
@ -520,7 +607,8 @@ composite_type (tree t1, tree t2)
|
|||
/* Function types: prefer the one that specified arg types.
|
||||
If both do, merge the arg types. Also merge the return types. */
|
||||
{
|
||||
tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
|
||||
tree valtype = composite_type_internal (TREE_TYPE (t1),
|
||||
TREE_TYPE (t2), cache);
|
||||
tree p1 = TYPE_ARG_TYPES (t1);
|
||||
tree p2 = TYPE_ARG_TYPES (t2);
|
||||
int len;
|
||||
|
|
@ -565,6 +653,16 @@ composite_type (tree t1, tree t2)
|
|||
for (; p1 && p1 != void_list_node;
|
||||
p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n))
|
||||
{
|
||||
tree mv1 = TREE_VALUE (p1);
|
||||
if (mv1 && mv1 != error_mark_node
|
||||
&& TREE_CODE (mv1) != ARRAY_TYPE)
|
||||
mv1 = TYPE_MAIN_VARIANT (mv1);
|
||||
|
||||
tree mv2 = TREE_VALUE (p2);
|
||||
if (mv2 && mv2 != error_mark_node
|
||||
&& TREE_CODE (mv2) != ARRAY_TYPE)
|
||||
mv2 = TYPE_MAIN_VARIANT (mv2);
|
||||
|
||||
/* A null type means arg type is not specified.
|
||||
Take whatever the other function type has. */
|
||||
if (TREE_VALUE (p1) == NULL_TREE)
|
||||
|
|
@ -585,10 +683,6 @@ composite_type (tree t1, tree t2)
|
|||
&& TREE_VALUE (p1) != TREE_VALUE (p2))
|
||||
{
|
||||
tree memb;
|
||||
tree mv2 = TREE_VALUE (p2);
|
||||
if (mv2 && mv2 != error_mark_node
|
||||
&& TREE_CODE (mv2) != ARRAY_TYPE)
|
||||
mv2 = TYPE_MAIN_VARIANT (mv2);
|
||||
for (memb = TYPE_FIELDS (TREE_VALUE (p1));
|
||||
memb; memb = DECL_CHAIN (memb))
|
||||
{
|
||||
|
|
@ -598,8 +692,9 @@ composite_type (tree t1, tree t2)
|
|||
mv3 = TYPE_MAIN_VARIANT (mv3);
|
||||
if (comptypes (mv3, mv2))
|
||||
{
|
||||
TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
|
||||
TREE_VALUE (p2));
|
||||
TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb),
|
||||
TREE_VALUE (p2),
|
||||
cache);
|
||||
pedwarn (input_location, OPT_Wpedantic,
|
||||
"function types not truly compatible in ISO C");
|
||||
goto parm_done;
|
||||
|
|
@ -610,10 +705,6 @@ composite_type (tree t1, tree t2)
|
|||
&& TREE_VALUE (p2) != TREE_VALUE (p1))
|
||||
{
|
||||
tree memb;
|
||||
tree mv1 = TREE_VALUE (p1);
|
||||
if (mv1 && mv1 != error_mark_node
|
||||
&& TREE_CODE (mv1) != ARRAY_TYPE)
|
||||
mv1 = TYPE_MAIN_VARIANT (mv1);
|
||||
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
|
||||
memb; memb = DECL_CHAIN (memb))
|
||||
{
|
||||
|
|
@ -623,15 +714,17 @@ composite_type (tree t1, tree t2)
|
|||
mv3 = TYPE_MAIN_VARIANT (mv3);
|
||||
if (comptypes (mv3, mv1))
|
||||
{
|
||||
TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
|
||||
TREE_VALUE (p1));
|
||||
TREE_VALUE (n)
|
||||
= composite_type_internal (TREE_TYPE (memb),
|
||||
TREE_VALUE (p1),
|
||||
cache);
|
||||
pedwarn (input_location, OPT_Wpedantic,
|
||||
"function types not truly compatible in ISO C");
|
||||
goto parm_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
|
||||
TREE_VALUE (n) = composite_type_internal (mv1, mv2, cache);
|
||||
parm_done: ;
|
||||
}
|
||||
|
||||
|
|
@ -643,7 +736,13 @@ composite_type (tree t1, tree t2)
|
|||
default:
|
||||
return build_type_attribute_variant (t1, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
tree
|
||||
composite_type (tree t1, tree t2)
|
||||
{
|
||||
struct composite_cache cache = { };
|
||||
return composite_type_internal (t1, t2, &cache);
|
||||
}
|
||||
|
||||
/* Return the type of a conditional expression between pointers to
|
||||
|
|
@ -1063,6 +1162,7 @@ struct comptypes_data {
|
|||
bool different_types_p;
|
||||
bool warning_needed;
|
||||
bool anon_field;
|
||||
bool equiv;
|
||||
|
||||
const struct tagged_tu_seen_cache* cache;
|
||||
};
|
||||
|
|
@ -1080,6 +1180,23 @@ comptypes (tree type1, tree type2)
|
|||
return ret ? (data.warning_needed ? 2 : 1) : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Like comptypes, but it returns non-zero only for identical
|
||||
types. */
|
||||
|
||||
bool
|
||||
comptypes_same_p (tree type1, tree type2)
|
||||
{
|
||||
struct comptypes_data data = { };
|
||||
bool ret = comptypes_internal (type1, type2, &data);
|
||||
|
||||
if (data.different_types_p)
|
||||
return false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Like comptypes, but if it returns non-zero because enum and int are
|
||||
compatible, it sets *ENUM_AND_INT_P to true. */
|
||||
|
||||
|
|
@ -1106,6 +1223,21 @@ comptypes_check_different_types (tree type1, tree type2,
|
|||
|
||||
return ret ? (data.warning_needed ? 2 : 1) : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Like comptypes, but if it returns nonzero for struct and union
|
||||
types considered equivalent for aliasing purposes. */
|
||||
|
||||
bool
|
||||
comptypes_equiv_p (tree type1, tree type2)
|
||||
{
|
||||
struct comptypes_data data = { };
|
||||
data.equiv = true;
|
||||
bool ret = comptypes_internal (type1, type2, &data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if TYPE1 and TYPE2 are compatible types for assignment
|
||||
or various other operations. If they are compatible but a warning may
|
||||
|
|
@ -1233,6 +1365,9 @@ comptypes_internal (const_tree type1, const_tree type2,
|
|||
|
||||
if ((d1 == NULL_TREE) != (d2 == NULL_TREE))
|
||||
data->different_types_p = true;
|
||||
/* Ignore size mismatches. */
|
||||
if (data->equiv)
|
||||
return true;
|
||||
/* Sizes must match unless one is missing or variable. */
|
||||
if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2)
|
||||
return true;
|
||||
|
|
@ -1266,11 +1401,11 @@ comptypes_internal (const_tree type1, const_tree type2,
|
|||
case ENUMERAL_TYPE:
|
||||
case RECORD_TYPE:
|
||||
case UNION_TYPE:
|
||||
if (false)
|
||||
{
|
||||
return tagged_types_tu_compatible_p (t1, t2, data);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (!flag_isoc23)
|
||||
return false;
|
||||
|
||||
return tagged_types_tu_compatible_p (t1, t2, data);
|
||||
|
||||
case VECTOR_TYPE:
|
||||
return known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
|
||||
|
|
@ -1376,8 +1511,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
|
|||
if (!data->anon_field && TYPE_STUB_DECL (t1) != TYPE_STUB_DECL (t2))
|
||||
data->different_types_p = true;
|
||||
|
||||
data->anon_field = false;
|
||||
|
||||
/* Incomplete types are incompatible inside a TU. */
|
||||
if (TYPE_SIZE (t1) == NULL || TYPE_SIZE (t2) == NULL)
|
||||
return false;
|
||||
|
|
@ -1402,6 +1535,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
|
|||
{
|
||||
case ENUMERAL_TYPE:
|
||||
{
|
||||
if (!comptypes (ENUM_UNDERLYING_TYPE (t1), ENUM_UNDERLYING_TYPE (t2)))
|
||||
return false;
|
||||
|
||||
/* Speed up the case where the type values are in the same order. */
|
||||
tree tv1 = TYPE_VALUES (t1);
|
||||
tree tv2 = TYPE_VALUES (t2);
|
||||
|
|
@ -1447,25 +1583,36 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
|
|||
if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
|
||||
return false;
|
||||
|
||||
if (data->equiv && (C_TYPE_VARIABLE_SIZE (t1) || C_TYPE_VARIABLE_SIZE (t2)))
|
||||
return false;
|
||||
|
||||
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
|
||||
s1 && s2;
|
||||
s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
|
||||
{
|
||||
if (TREE_CODE (s1) != TREE_CODE (s2)
|
||||
|| DECL_NAME (s1) != DECL_NAME (s2))
|
||||
gcc_assert (TREE_CODE (s1) == FIELD_DECL);
|
||||
gcc_assert (TREE_CODE (s2) == FIELD_DECL);
|
||||
|
||||
if (DECL_NAME (s1) != DECL_NAME (s2))
|
||||
return false;
|
||||
|
||||
if (!DECL_NAME (s1) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (s1)))
|
||||
data->anon_field = true;
|
||||
if (DECL_ALIGN (s1) != DECL_ALIGN (s2))
|
||||
return false;
|
||||
|
||||
data->anon_field = !DECL_NAME (s1);
|
||||
|
||||
data->cache = &entry;
|
||||
if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data))
|
||||
return false;
|
||||
|
||||
if (TREE_CODE (s1) == FIELD_DECL
|
||||
&& simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
|
||||
DECL_FIELD_BIT_OFFSET (s2)) != 1)
|
||||
return false;
|
||||
tree st1 = TYPE_SIZE (TREE_TYPE (s1));
|
||||
tree st2 = TYPE_SIZE (TREE_TYPE (s2));
|
||||
|
||||
if (data->equiv
|
||||
&& st1 && TREE_CODE (st1) == INTEGER_CST
|
||||
&& st2 && TREE_CODE (st2) == INTEGER_CST
|
||||
&& !tree_int_cst_equal (st1, st2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
|
|
@ -5515,6 +5662,11 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
|
|||
result_type = type2;
|
||||
else if (code1 == POINTER_TYPE && code2 == NULLPTR_TYPE)
|
||||
result_type = type1;
|
||||
else if (RECORD_OR_UNION_TYPE_P (type1) && RECORD_OR_UNION_TYPE_P (type2)
|
||||
&& comptypes (TYPE_MAIN_VARIANT (type1),
|
||||
TYPE_MAIN_VARIANT (type2)))
|
||||
result_type = composite_type (TYPE_MAIN_VARIANT (type1),
|
||||
TYPE_MAIN_VARIANT (type2));
|
||||
|
||||
if (!result_type)
|
||||
{
|
||||
|
|
@ -6054,6 +6206,19 @@ build_c_cast (location_t loc, tree type, tree expr)
|
|||
c_addr_space_name (as_to),
|
||||
c_addr_space_name (as_from));
|
||||
}
|
||||
|
||||
/* Warn of new allocations that are not big enough for the target
|
||||
type. */
|
||||
if (warn_alloc_size && TREE_CODE (value) == CALL_EXPR)
|
||||
if (tree fndecl = get_callee_fndecl (value))
|
||||
if (DECL_IS_MALLOC (fndecl))
|
||||
{
|
||||
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
|
||||
tree alloc_size = lookup_attribute ("alloc_size", attrs);
|
||||
if (alloc_size)
|
||||
warn_for_alloc_size (loc, TREE_TYPE (type), value,
|
||||
alloc_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Warn about possible alignment problems. */
|
||||
|
|
@ -6989,7 +7154,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
|
|||
if (checktype != error_mark_node
|
||||
&& TREE_CODE (checktype) == ENUMERAL_TYPE
|
||||
&& TREE_CODE (type) == ENUMERAL_TYPE
|
||||
&& TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type))
|
||||
&& !comptypes (TYPE_MAIN_VARIANT (checktype), TYPE_MAIN_VARIANT (type)))
|
||||
{
|
||||
gcc_rich_location loc (location);
|
||||
warning_at (&loc, OPT_Wenum_conversion,
|
||||
|
|
@ -7089,7 +7254,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
|
|||
/* Aggregates in different TUs might need conversion. */
|
||||
if ((codel == RECORD_TYPE || codel == UNION_TYPE)
|
||||
&& codel == coder
|
||||
&& comptypes (type, rhstype))
|
||||
&& comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (rhstype)))
|
||||
return convert_and_check (expr_loc != UNKNOWN_LOCATION
|
||||
? expr_loc : location, type, rhs);
|
||||
|
||||
|
|
@ -7277,32 +7442,15 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
|
|||
|
||||
/* Warn of new allocations that are not big enough for the target
|
||||
type. */
|
||||
tree fndecl;
|
||||
if (warn_alloc_size
|
||||
&& TREE_CODE (rhs) == CALL_EXPR
|
||||
&& (fndecl = get_callee_fndecl (rhs)) != NULL_TREE
|
||||
&& DECL_IS_MALLOC (fndecl))
|
||||
{
|
||||
tree fntype = TREE_TYPE (fndecl);
|
||||
tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
|
||||
tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs);
|
||||
if (alloc_size)
|
||||
if (warn_alloc_size && TREE_CODE (rhs) == CALL_EXPR)
|
||||
if (tree fndecl = get_callee_fndecl (rhs))
|
||||
if (DECL_IS_MALLOC (fndecl))
|
||||
{
|
||||
tree args = TREE_VALUE (alloc_size);
|
||||
int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
|
||||
/* For calloc only use the second argument. */
|
||||
if (TREE_CHAIN (args))
|
||||
idx = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
|
||||
tree arg = CALL_EXPR_ARG (rhs, idx);
|
||||
if (TREE_CODE (arg) == INTEGER_CST
|
||||
&& !VOID_TYPE_P (ttl) && TYPE_SIZE_UNIT (ttl)
|
||||
&& INTEGER_CST == TREE_CODE (TYPE_SIZE_UNIT (ttl))
|
||||
&& tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
|
||||
warning_at (location, OPT_Walloc_size, "allocation of "
|
||||
"insufficient size %qE for type %qT with "
|
||||
"size %qE", arg, ttl, TYPE_SIZE_UNIT (ttl));
|
||||
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
|
||||
tree alloc_size = lookup_attribute ("alloc_size", attrs);
|
||||
if (alloc_size)
|
||||
warn_for_alloc_size (location, ttl, rhs, alloc_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* See if the pointers point to incompatible address spaces. */
|
||||
asl = TYPE_ADDR_SPACE (ttl);
|
||||
|
|
@ -8461,6 +8609,13 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
|
|||
conversion. */
|
||||
inside_init = convert (type, inside_init);
|
||||
|
||||
if ((code == RECORD_TYPE || code == UNION_TYPE)
|
||||
&& !comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (TREE_TYPE (inside_init))))
|
||||
{
|
||||
error_init (init_loc, "invalid initializer");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (require_constant
|
||||
&& TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
|
||||
{
|
||||
|
|
@ -10546,7 +10701,7 @@ initialize_elementwise_p (tree type, tree value)
|
|||
return !VECTOR_TYPE_P (value_type);
|
||||
|
||||
if (AGGREGATE_TYPE_P (type))
|
||||
return type != TYPE_MAIN_VARIANT (value_type);
|
||||
return !comptypes (type, TYPE_MAIN_VARIANT (value_type));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1487,9 +1487,12 @@ c_parser_gimple_postfix_expression (gimple_parser &parser)
|
|||
location_t loc = c_parser_peek_token (parser)->location;
|
||||
c_parser_consume_token (parser);
|
||||
tree type = c_parser_gimple_typespec (parser);
|
||||
struct c_expr ptr;
|
||||
struct c_expr ptr, alias_off, step, index, index2;
|
||||
ptr.value = error_mark_node;
|
||||
tree alias_off = NULL_TREE;
|
||||
alias_off.value = NULL_TREE;
|
||||
step.value = NULL_TREE;
|
||||
index.value = NULL_TREE;
|
||||
index2.value = NULL_TREE;
|
||||
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
|
||||
{
|
||||
tree alias_type = NULL_TREE;
|
||||
|
|
@ -1525,12 +1528,52 @@ c_parser_gimple_postfix_expression (gimple_parser &parser)
|
|||
if (c_parser_next_token_is (parser, CPP_PLUS))
|
||||
{
|
||||
c_parser_consume_token (parser);
|
||||
alias_off
|
||||
= c_parser_gimple_postfix_expression (parser).value;
|
||||
alias_off = fold_convert (alias_type, alias_off);
|
||||
alias_off = c_parser_gimple_postfix_expression (parser);
|
||||
}
|
||||
if (c_parser_next_token_is (parser, CPP_MULT))
|
||||
{
|
||||
std::swap (index, alias_off);
|
||||
c_parser_consume_token (parser);
|
||||
step = c_parser_gimple_postfix_expression (parser);
|
||||
}
|
||||
else if (c_parser_next_token_is (parser, CPP_PLUS))
|
||||
{
|
||||
c_parser_consume_token (parser);
|
||||
index = c_parser_gimple_postfix_expression (parser);
|
||||
if (c_parser_next_token_is (parser, CPP_MULT))
|
||||
{
|
||||
c_parser_consume_token (parser);
|
||||
step = c_parser_gimple_postfix_expression (parser);
|
||||
}
|
||||
else
|
||||
std::swap (index, index2);
|
||||
}
|
||||
else if (alias_off.value
|
||||
&& TREE_CODE (alias_off.value) != INTEGER_CST)
|
||||
std::swap (alias_off, index2);
|
||||
if (c_parser_next_token_is (parser, CPP_PLUS))
|
||||
{
|
||||
c_parser_consume_token (parser);
|
||||
index2 = c_parser_gimple_postfix_expression (parser);
|
||||
}
|
||||
if (alias_off.value)
|
||||
{
|
||||
if (TREE_CODE (alias_off.value) != INTEGER_CST)
|
||||
error_at (alias_off.get_start (),
|
||||
"expected constant offset for %<__MEM%> "
|
||||
"operand");
|
||||
alias_off.value = fold_convert (alias_type,
|
||||
alias_off.value);
|
||||
}
|
||||
else
|
||||
alias_off.value = build_int_cst (alias_type, 0);
|
||||
if (step.value)
|
||||
{
|
||||
if (TREE_CODE (step.value) != INTEGER_CST)
|
||||
error_at (step.get_start (),
|
||||
"expected constant step for %<__MEM%> "
|
||||
"operand");
|
||||
}
|
||||
if (! alias_off)
|
||||
alias_off = build_int_cst (alias_type, 0);
|
||||
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
|
||||
"expected %<)%>");
|
||||
}
|
||||
|
|
@ -1539,8 +1582,13 @@ c_parser_gimple_postfix_expression (gimple_parser &parser)
|
|||
c_parser_set_error (parser, false);
|
||||
return expr;
|
||||
}
|
||||
expr.value = build2_loc (loc, MEM_REF,
|
||||
type, ptr.value, alias_off);
|
||||
if (index.value || step.value || index2.value)
|
||||
expr.value = build5_loc (loc, TARGET_MEM_REF,
|
||||
type, ptr.value, alias_off.value,
|
||||
index.value, step.value, index2.value);
|
||||
else
|
||||
expr.value = build2_loc (loc, MEM_REF,
|
||||
type, ptr.value, alias_off.value);
|
||||
break;
|
||||
}
|
||||
else if (strcmp (IDENTIFIER_POINTER (id), "__VIEW_CONVERT") == 0)
|
||||
|
|
|
|||
|
|
@ -2092,7 +2092,13 @@ commit_one_edge_insertion (edge e)
|
|||
delete_insn (before);
|
||||
}
|
||||
else
|
||||
gcc_assert (!JUMP_P (last));
|
||||
/* Some builtin expanders, such as those for memset and memcpy,
|
||||
may generate loops and conditionals, and those may get emitted
|
||||
into edges. That's ok while expanding to rtl, basic block
|
||||
boundaries will be identified and split afterwards. ??? Need
|
||||
we check whether the destination labels of any inserted jumps
|
||||
are also part of the inserted sequence? */
|
||||
gcc_assert (!JUMP_P (last) || currently_expanding_to_rtl);
|
||||
}
|
||||
|
||||
/* Update the CFG for all queued instructions. */
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "tree-eh.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "tree-inline.h"
|
||||
#include "attribs.h"
|
||||
#include "dumpfile.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "alloc-pool.h"
|
||||
|
|
@ -1048,7 +1049,17 @@ cgraph_node::create_version_clone_with_body
|
|||
location_t saved_loc = input_location;
|
||||
tree v = TREE_VALUE (target_attributes);
|
||||
input_location = DECL_SOURCE_LOCATION (new_decl);
|
||||
bool r = targetm.target_option.valid_attribute_p (new_decl, NULL, v, 1);
|
||||
bool r;
|
||||
tree name_id = get_attribute_name (target_attributes);
|
||||
const char *name_str = IDENTIFIER_POINTER (name_id);
|
||||
if (strcmp (name_str, "target") == 0)
|
||||
r = targetm.target_option.valid_attribute_p (new_decl, name_id, v, 1);
|
||||
else if (strcmp (name_str, "target_version") == 0)
|
||||
r = targetm.target_option.valid_version_attribute_p (new_decl, name_id,
|
||||
v, 1);
|
||||
else
|
||||
gcc_unreachable();
|
||||
|
||||
input_location = saved_loc;
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -622,7 +622,7 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
|
|||
LTO object replaced by all partitions and other LTO
|
||||
objects removed. */
|
||||
|
||||
lto_c_argv = (char **) xcalloc (sizeof (char *), num_lto_c_args);
|
||||
lto_c_argv = (char **) xcalloc (num_lto_c_args, sizeof (char *));
|
||||
lto_c_ptr = CONST_CAST2 (const char **, char **, lto_c_argv);
|
||||
|
||||
*lto_c_ptr++ = lto_wrapper;
|
||||
|
|
|
|||
|
|
@ -8227,12 +8227,20 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
|
|||
int sub_width;
|
||||
if ((REG_P (sub) || MEM_P (sub))
|
||||
&& GET_MODE_PRECISION (sub_mode).is_constant (&sub_width)
|
||||
&& sub_width < mode_width)
|
||||
&& sub_width < mode_width
|
||||
&& (!WORD_REGISTER_OPERATIONS
|
||||
|| sub_width >= BITS_PER_WORD
|
||||
/* On WORD_REGISTER_OPERATIONS targets the bits
|
||||
beyond sub_mode aren't considered undefined,
|
||||
so optimize only if it is a MEM load when MEM loads
|
||||
zero extend, because then the upper bits are all zero. */
|
||||
|| (MEM_P (sub)
|
||||
&& load_extend_op (sub_mode) == ZERO_EXTEND)))
|
||||
{
|
||||
unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (sub_mode);
|
||||
unsigned HOST_WIDE_INT mask;
|
||||
|
||||
/* original AND constant with all the known zero bits set */
|
||||
/* Original AND constant with all the known zero bits set. */
|
||||
mask = UINTVAL (XEXP (x, 1)) | (~nonzero_bits (sub, sub_mode));
|
||||
if ((mask & mode_mask) == mode_mask)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,9 +149,6 @@ struct aarch64_option_extension
|
|||
aarch64_feature_flags flags_on;
|
||||
/* If this feature is turned off, these bits also need to be turned off. */
|
||||
aarch64_feature_flags flags_off;
|
||||
/* Indicates whether this feature is taken into account during native cpu
|
||||
detection. */
|
||||
bool native_detect_p;
|
||||
};
|
||||
|
||||
/* ISA extensions in AArch64. */
|
||||
|
|
@ -159,10 +156,9 @@ static constexpr aarch64_option_extension all_extensions[] =
|
|||
{
|
||||
#define AARCH64_OPT_EXTENSION(NAME, IDENT, C, D, E, FEATURE_STRING) \
|
||||
{NAME, AARCH64_FL_##IDENT, feature_deps::IDENT ().explicit_on, \
|
||||
feature_deps::get_flags_off (feature_deps::root_off_##IDENT), \
|
||||
FEATURE_STRING[0]},
|
||||
feature_deps::get_flags_off (feature_deps::root_off_##IDENT)},
|
||||
#include "config/aarch64/aarch64-option-extensions.def"
|
||||
{NULL, 0, 0, 0, false}
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
struct processor_name_to_arch
|
||||
|
|
@ -311,6 +307,7 @@ aarch64_get_extension_string_for_isa_flags
|
|||
But in order to make the output more readable, it seems better
|
||||
to add the strings in definition order. */
|
||||
aarch64_feature_flags added = 0;
|
||||
auto flags_crypto = AARCH64_FL_AES | AARCH64_FL_SHA2;
|
||||
for (unsigned int i = ARRAY_SIZE (all_extensions); i-- > 0; )
|
||||
{
|
||||
auto &opt = all_extensions[i];
|
||||
|
|
@ -320,7 +317,7 @@ aarch64_get_extension_string_for_isa_flags
|
|||
per-feature crypto flags. */
|
||||
auto flags = opt.flag_canonical;
|
||||
if (flags == AARCH64_FL_CRYPTO)
|
||||
flags = AARCH64_FL_AES | AARCH64_FL_SHA2;
|
||||
flags = flags_crypto;
|
||||
|
||||
if ((flags & isa_flags & (explicit_flags | ~current_flags)) == flags)
|
||||
{
|
||||
|
|
@ -339,14 +336,31 @@ aarch64_get_extension_string_for_isa_flags
|
|||
not have an HWCAPs then it shouldn't be taken into account for feature
|
||||
detection because one way or another we can't tell if it's available
|
||||
or not. */
|
||||
|
||||
for (auto &opt : all_extensions)
|
||||
if (opt.native_detect_p
|
||||
&& (opt.flag_canonical & current_flags & ~isa_flags))
|
||||
{
|
||||
current_flags &= ~opt.flags_off;
|
||||
outstr += "+no";
|
||||
outstr += opt.name;
|
||||
}
|
||||
{
|
||||
auto flags = opt.flag_canonical;
|
||||
/* As a special case, don't emit "+noaes" or "+nosha2" when we could emit
|
||||
"+nocrypto" instead, in order to support assemblers that predate the
|
||||
separate per-feature crypto flags. Only allow "+nocrypto" when "sm4"
|
||||
is not already enabled (to avoid dependending on whether "+nocrypto"
|
||||
also disables "sm4"). */
|
||||
if (flags & flags_crypto
|
||||
&& (flags_crypto & current_flags & ~isa_flags) == flags_crypto
|
||||
&& !(current_flags & AARCH64_FL_SM4))
|
||||
continue;
|
||||
|
||||
if (flags == AARCH64_FL_CRYPTO)
|
||||
/* If either crypto flag needs removing here, then both do. */
|
||||
flags = flags_crypto;
|
||||
|
||||
if (flags & current_flags & ~isa_flags)
|
||||
{
|
||||
current_flags &= ~opt.flags_off;
|
||||
outstr += "+no";
|
||||
outstr += opt.name;
|
||||
}
|
||||
}
|
||||
|
||||
return outstr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/* CPU feature detection for AArch64 architecture.
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This enum is used in libgcc feature detection, and in the function
|
||||
multiversioning implementation in aarch64.cc. The enum should use the same
|
||||
values as the corresponding enum in LLVM's compiler-rt, to faciliate
|
||||
compatibility between compilers. */
|
||||
|
||||
enum CPUFeatures {
|
||||
FEAT_RNG,
|
||||
FEAT_FLAGM,
|
||||
FEAT_FLAGM2,
|
||||
FEAT_FP16FML,
|
||||
FEAT_DOTPROD,
|
||||
FEAT_SM4,
|
||||
FEAT_RDM,
|
||||
FEAT_LSE,
|
||||
FEAT_FP,
|
||||
FEAT_SIMD,
|
||||
FEAT_CRC,
|
||||
FEAT_SHA1,
|
||||
FEAT_SHA2,
|
||||
FEAT_SHA3,
|
||||
FEAT_AES,
|
||||
FEAT_PMULL,
|
||||
FEAT_FP16,
|
||||
FEAT_DIT,
|
||||
FEAT_DPB,
|
||||
FEAT_DPB2,
|
||||
FEAT_JSCVT,
|
||||
FEAT_FCMA,
|
||||
FEAT_RCPC,
|
||||
FEAT_RCPC2,
|
||||
FEAT_FRINTTS,
|
||||
FEAT_DGH,
|
||||
FEAT_I8MM,
|
||||
FEAT_BF16,
|
||||
FEAT_EBF16,
|
||||
FEAT_RPRES,
|
||||
FEAT_SVE,
|
||||
FEAT_SVE_BF16,
|
||||
FEAT_SVE_EBF16,
|
||||
FEAT_SVE_I8MM,
|
||||
FEAT_SVE_F32MM,
|
||||
FEAT_SVE_F64MM,
|
||||
FEAT_SVE2,
|
||||
FEAT_SVE_AES,
|
||||
FEAT_SVE_PMULL128,
|
||||
FEAT_SVE_BITPERM,
|
||||
FEAT_SVE_SHA3,
|
||||
FEAT_SVE_SM4,
|
||||
FEAT_SME,
|
||||
FEAT_MEMTAG,
|
||||
FEAT_MEMTAG2,
|
||||
FEAT_MEMTAG3,
|
||||
FEAT_SB,
|
||||
FEAT_PREDRES,
|
||||
FEAT_SSBS,
|
||||
FEAT_SSBS2,
|
||||
FEAT_BTI,
|
||||
FEAT_LS64,
|
||||
FEAT_LS64_V,
|
||||
FEAT_LS64_ACCDATA,
|
||||
FEAT_WFXT,
|
||||
FEAT_SME_F64,
|
||||
FEAT_SME_I64,
|
||||
FEAT_SME2,
|
||||
FEAT_RCPC3,
|
||||
FEAT_MAX,
|
||||
FEAT_EXT = 62, /* Reserved to indicate presence of additional features field
|
||||
in __aarch64_cpu_features. */
|
||||
FEAT_INIT /* Used as flag of features initialization completion. */
|
||||
};
|
||||
|
|
@ -160,6 +160,7 @@ static const riscv_implied_info_t riscv_implied_info[] =
|
|||
|
||||
{"zfa", "f"},
|
||||
|
||||
{"zvfbfmin", "zve32f"},
|
||||
{"zvfhmin", "zve32f"},
|
||||
{"zvfh", "zve32f"},
|
||||
{"zvfh", "zfhmin"},
|
||||
|
|
@ -322,6 +323,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
|
|||
|
||||
{"zfh", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"zfhmin", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"zvfbfmin", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"zvfhmin", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"zvfh", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
|
||||
|
|
@ -352,6 +354,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
|
|||
|
||||
{"xcvmac", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"xcvalu", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"xcvelw", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
|
||||
{"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
{"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
|
||||
|
|
@ -1666,6 +1669,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
|
|||
{"zve64x", &gcc_options::x_riscv_vector_elen_flags, MASK_VECTOR_ELEN_64},
|
||||
{"zve64f", &gcc_options::x_riscv_vector_elen_flags, MASK_VECTOR_ELEN_FP_32},
|
||||
{"zve64d", &gcc_options::x_riscv_vector_elen_flags, MASK_VECTOR_ELEN_FP_64},
|
||||
{"zvfbfmin", &gcc_options::x_riscv_vector_elen_flags, MASK_VECTOR_ELEN_BF_16},
|
||||
{"zvfhmin", &gcc_options::x_riscv_vector_elen_flags, MASK_VECTOR_ELEN_FP_16},
|
||||
{"zvfh", &gcc_options::x_riscv_vector_elen_flags, MASK_VECTOR_ELEN_FP_16},
|
||||
|
||||
|
|
@ -1701,6 +1705,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
|
|||
|
||||
{"zfhmin", &gcc_options::x_riscv_zf_subext, MASK_ZFHMIN},
|
||||
{"zfh", &gcc_options::x_riscv_zf_subext, MASK_ZFH},
|
||||
{"zvfbfmin", &gcc_options::x_riscv_zf_subext, MASK_ZVFBFMIN},
|
||||
{"zvfhmin", &gcc_options::x_riscv_zf_subext, MASK_ZVFHMIN},
|
||||
{"zvfh", &gcc_options::x_riscv_zf_subext, MASK_ZVFH},
|
||||
|
||||
|
|
@ -1724,6 +1729,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
|
|||
|
||||
{"xcvmac", &gcc_options::x_riscv_xcv_subext, MASK_XCVMAC},
|
||||
{"xcvalu", &gcc_options::x_riscv_xcv_subext, MASK_XCVALU},
|
||||
{"xcvelw", &gcc_options::x_riscv_xcv_subext, MASK_XCVELW},
|
||||
|
||||
{"xtheadba", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
|
||||
{"xtheadbb", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ aarch64*-*-*)
|
|||
c_target_objs="aarch64-c.o"
|
||||
cxx_target_objs="aarch64-c.o"
|
||||
d_target_objs="aarch64-d.o"
|
||||
extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o aarch64-sve-builtins-sme.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch-bti-insert.o aarch64-cc-fusion.o aarch64-early-ra.o"
|
||||
extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o aarch64-sve-builtins-sme.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch-bti-insert.o aarch64-cc-fusion.o aarch64-early-ra.o aarch64-ldp-fusion.o"
|
||||
target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.cc \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc"
|
||||
target_has_targetm_common=yes
|
||||
;;
|
||||
|
|
@ -482,6 +482,7 @@ mips*-*-*)
|
|||
;;
|
||||
loongarch*-*-*)
|
||||
cpu_type=loongarch
|
||||
d_target_objs="loongarch-d.o"
|
||||
extra_headers="larchintrin.h lsxintrin.h lasxintrin.h"
|
||||
extra_objs="loongarch-c.o loongarch-builtins.o loongarch-cpu.o loongarch-opts.o loongarch-def.o"
|
||||
extra_gcc_objs="loongarch-driver.o loongarch-cpu.o loongarch-opts.o loongarch-def.o"
|
||||
|
|
|
|||
|
|
@ -793,6 +793,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* Define if your assembler supports tls le relocation. */
|
||||
#ifndef USED_FOR_TARGET
|
||||
#undef HAVE_AS_TLS_LE_RELAXATION
|
||||
#endif
|
||||
|
||||
|
||||
/* Define if your assembler supports vl/vst/vlm/vstm with an optional
|
||||
alignment hint argument. */
|
||||
#ifndef USED_FOR_TARGET
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue