Merge commit 'a945c346f57ba40fc80c14ac59be0d43624e559d^' into HEAD

This commit is contained in:
Thomas Schwinge 2024-03-22 09:26:05 +01:00
commit 884c2b766e
1755 changed files with 169511 additions and 135821 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ([

File diff suppressed because it is too large Load Diff

54880
gcc/ChangeLog-2023 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
20231214
20240103

View File

@ -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

File diff suppressed because it is too large Load Diff

6978
gcc/ada/ChangeLog-2023 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,9 @@
#include "system.h"
#endif
#ifndef LIGHT_RUNTIME
#include "adaint.h"
#endif
#ifdef __cplusplus
extern "C" {

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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

View File

@ -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 --

View File

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

View File

@ -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

View File

@ -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

View File

@ -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 --
----------------------------------

View File

@ -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

View File

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

View File

@ -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).

View File

@ -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

View File

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

View File

@ -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);

View File

@ -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,

View File

@ -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)));

View File

@ -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),

View File

@ -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 =>

View File

@ -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 Documents 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 works 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 proxys 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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.

View File

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

View File

@ -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.

View File

@ -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.

View File

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

View File

@ -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 --
---------------

View File

@ -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

View File

@ -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 --
------------------------------

View File

@ -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

View File

@ -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 --

View File

@ -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 =>

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

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

View File

@ -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
{

View File

@ -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

View File

@ -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 ();

View File

@ -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. */

View File

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

View File

@ -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,

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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. */

View File

@ -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

View File

@ -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");

View File

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

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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.

View File

@ -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

View File

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

View File

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

View File

@ -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))
{

View File

@ -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);

View File

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

View File

@ -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)

View File

@ -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. */

View File

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

View File

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

View File

@ -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)
{

View File

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

View File

@ -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. */
};

View File

@ -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},

View File

@ -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"

View File

@ -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