--  Semantic analysis pass.
--  Copyright (C) 2002, 2003, 2004, 2005 Tristan Gingold
--
--  This program 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 2 of the License, or
--  (at your option) any later version.
--
--  This program 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.
--
--  You should have received a copy of the GNU General Public License
--  along with this program.  If not, see <gnu.org/licenses>.

with Errorout; use Errorout;
with Libraries;
with Std_Names;
with Flags; use Flags;
with Str_Table;

with Vhdl.Errors; use Vhdl.Errors;
with Vhdl.Std_Package; use Vhdl.Std_Package;
with Vhdl.Ieee.Std_Logic_1164;
with Vhdl.Sem_Scopes; use Vhdl.Sem_Scopes;
with Vhdl.Sem_Expr; use Vhdl.Sem_Expr;
with Vhdl.Sem_Names; use Vhdl.Sem_Names;
with Vhdl.Sem_Specs; use Vhdl.Sem_Specs;
with Vhdl.Sem_Decls; use Vhdl.Sem_Decls;
with Vhdl.Sem_Assocs; use Vhdl.Sem_Assocs;
with Vhdl.Sem_Types;
with Vhdl.Sem_Inst;
with Vhdl.Sem_Lib; use Vhdl.Sem_Lib;
with Vhdl.Sem_Psl;
with Vhdl.Utils; use Vhdl.Utils;
with Vhdl.Sem_Utils;
with Vhdl.Sem_Stmts; use Vhdl.Sem_Stmts;
with Vhdl.Nodes_Utils;
with Vhdl.Xrefs; use Vhdl.Xrefs;
with Vhdl.Elocations;

package body Vhdl.Sem is
   -- Forward declarations.
   procedure Sem_Context_Clauses (Unit: Iir);
   procedure Sem_Block_Configuration
     (Block_Conf : Iir_Block_Configuration; Father: Iir);
   procedure Sem_Component_Configuration
     (Conf : Iir_Component_Configuration; Father : Iir);

   procedure Add_Dependence (Unit : Iir)
   is
      Targ : constant Iir := Get_Current_Design_Unit;
   begin
      --  During normal analysis, there is a current design unit.  But not
      --  during debugging outside of any context.
      if Targ = Null_Iir then
         return;
      end if;

      Add_Dependence (Targ, Unit);
   end Add_Dependence;

   --  LRM 1.1  Entity declaration.
   procedure Sem_Entity_Declaration (Entity : Iir_Entity_Declaration)
   is
      Generics : constant Iir := Get_Generic_Chain (Entity);
   begin
      Xrefs.Xref_Decl (Entity);
      Sem_Scopes.Add_Name (Entity);
      Set_Visible_Flag (Entity, True);

      Set_Is_Within_Flag (Entity, True);

      --  LRM 10.1
      --  1.  An entity declaration, together with a corresponding architecture
      --      body.
      Open_Declarative_Region;

      -- Sem generics.
      Sem_Interface_Chain (Generics, Generic_Interface_List);

      --  Set macro-expand flag.
      if Component_Need_Instance (Entity, False) then
         Set_Macro_Expand_Flag (Entity, True);
      end if;

      -- Sem ports.
      Sem_Interface_Chain (Get_Port_Chain (Entity), Port_Interface_List);

      --  Entity declarative part and concurrent statements.
      Sem_Block (Entity);

      Close_Declarative_Region;
      Set_Is_Within_Flag (Entity, False);
   end Sem_Entity_Declaration;

   --  Get the entity unit for LIBRARY_UNIT (an architecture or a
   --  configuration declaration).
   --  Return NULL_IIR in case of error (not found, bad library).
   function Sem_Entity_Name (Library_Unit : Iir) return Iir
   is
      Name : Iir;
      Library : Iir_Library_Declaration;
      Entity : Iir;
   begin
      --  Get the library of architecture/configuration.
      Library := Get_Library
        (Get_Design_File (Get_Design_Unit (Library_Unit)));

      --  Resolve the name.

      Name := Get_Entity_Name (Library_Unit);
      if Is_Error (Name) then
         pragma Assert (Flags.Flag_Force_Analysis);
         return Null_Iir;
      end if;

      if Get_Kind (Name) = Iir_Kind_Simple_Name then
         --  LRM93 10.1 Declarative Region
         --  LRM08 12.1 Declarative Region
         --  a) An entity declaration, tohether with a corresponding
         --     architecture body.
         --
         --  GHDL: simple name needs to be handled specially.  Because
         --  architecture body is in the declarative region of its entity,
         --  the entity name is directly visible.  But we cannot really use
         --  that rule as is, as we don't know which is the entity.
         Entity := Load_Primary_Unit
           (Library, Get_Identifier (Name), Library_Unit);
         if Entity = Null_Iir then
            Error_Msg_Sem (+Name, "entity %n was not analysed", +Name);
            return Null_Iir;
         end if;
         Entity := Get_Library_Unit (Entity);
         Set_Named_Entity (Name, Entity);
         Xrefs.Xref_Ref (Name, Entity);
      elsif Get_Kind (Name) not in Iir_Kinds_Denoting_Name then
         Error_Msg_Sem (+Name, "entity name expected");
         return Null_Iir;
      else
         --  Certainly an expanded name.  Use the standard name analysis.
         Name := Sem_Denoting_Name (Name);
         Set_Entity_Name (Library_Unit, Name);
         Entity := Get_Named_Entity (Name);
      end if;

      if Get_Kind (Entity) /= Iir_Kind_Entity_Declaration then
         Error_Class_Match (Name, "entity");
         return Null_Iir;
      end if;

      --  LRM 1.2 Architecture bodies
      --  For a given design entity, both the entity declaration and the
      --  associated architecture body must reside in the same library.

      --  LRM 1.3 Configuration Declarations
      --  For a configuration of a given design entity, both the
      --  configuration declaration and the corresponding entity
      --  declaration must reside in the same library.
      if Get_Library (Get_Design_File (Get_Design_Unit (Entity))) /= Library
      then
         Error_Msg_Sem
           (+Library_Unit, "%n does not reside in %n", (+Entity, +Library));
         return Null_Iir;
      end if;

      return Entity;
   end Sem_Entity_Name;

   --  LRM 1.2  Architecture bodies.
   procedure Sem_Architecture_Body (Arch: Iir_Architecture_Body)
   is
      Entity_Unit : Iir_Design_Unit;
      Entity_Library : Iir_Entity_Declaration;
   begin
      Xrefs.Xref_Decl (Arch);
      -- First, find the entity.
      Entity_Library := Sem_Entity_Name (Arch);
      if Entity_Library = Null_Iir then
         return;
      end if;
      Entity_Unit := Get_Design_Unit (Entity_Library);

      --  LRM93 11.4
      --   In each case, the second unit depends on the first unit.
      --  GHDL: an architecture depends on its entity.
      Add_Dependence (Entity_Unit);

      Add_Context_Clauses (Entity_Unit);

      Set_Is_Within_Flag (Arch, True);
      Set_Is_Within_Flag (Entity_Library, True);

      --  Makes the entity name visible.
      --  FIXME: quote LRM.
      declare
         Prev_Hide : constant Boolean := Is_Warning_Enabled (Warnid_Hide);
      begin
         --  Avoid spurious warning from entity name (if it has the same
         --   identifier as a library clause).
         Enable_Warning (Warnid_Hide, False);
         Sem_Scopes.Add_Name
           (Entity_Library, Get_Identifier (Entity_Library), False);
         Enable_Warning (Warnid_Hide, Prev_Hide);
      end;

      --  LRM 10.1 Declarative Region
      --  1. An entity declaration, together with a corresponding architecture
      --     body.
      Open_Declarative_Region;
      Sem_Scopes.Add_Entity_Declarations (Entity_Library);

      --  LRM02 1.2  Architecture bodies
      --  For the purpose of interpreting the scope and visibility of the
      --  identifier (see 10.2 and 10.3), the declaration of the identifier is
      --  considered to occur after the final declarative item of the entity
      --  declarative part of the corresponding entity declaration.
      --
      --  FIXME: before VHDL-02, an architecture is not a declaration.
      Sem_Scopes.Add_Name (Arch, Get_Identifier (Arch), True);
      Set_Visible_Flag (Arch, True);

      --  LRM02 10.1  Declarative region
      --  The declarative region associated with an architecture body is
      --  considered to occur immediatly within the declarative region
      --  associated with the entity declaration corresponding to the given
      --  architecture body.
      --
      --  GHDL: this is only in vhdl-2002.
      if Vhdl_Std = Vhdl_02 then
         Open_Declarative_Region;
      end if;

      Current_Psl_Default_Clock := Null_Iir;
      Sem_Block (Arch);

      if Vhdl_Std = Vhdl_02 then
         Close_Declarative_Region;
      end if;

      Close_Declarative_Region;
      Set_Is_Within_Flag (Arch, False);
      Set_Is_Within_Flag (Entity_Library, False);
   end Sem_Architecture_Body;

   --  Return the real resolver used for (sub) object OBJ.
   --  Return NULL_IIR if none.
   function Get_Resolver (Obj : Iir) return Iir
   is
      Obj_Type : Iir;
      Res : Iir;
   begin
      case Get_Kind (Obj) is
         when Iir_Kind_Indexed_Name
           | Iir_Kind_Slice_Name
           | Iir_Kind_Selected_Element =>
            Res := Get_Resolver (Get_Prefix (Obj));
            if Res /= Null_Iir then
               return Res;
            end if;
         when Iir_Kind_Signal_Declaration
           | Iir_Kind_Interface_Signal_Declaration
           | Iir_Kind_Guard_Signal_Declaration
           | Iir_Kind_External_Signal_Name =>
            null;
         when Iir_Kind_Object_Alias_Declaration =>
            return Get_Resolver (Get_Name (Obj));
         when Iir_Kind_Simple_Name
           | Iir_Kind_Selected_Name =>
            return Get_Resolver (Get_Named_Entity (Obj));
         when others =>
            Error_Kind ("get_resolved", Obj);
      end case;

      Obj_Type := Get_Type (Obj);
      if Get_Kind (Obj_Type) in Iir_Kinds_Subtype_Definition then
         return Get_Resolution_Indication (Obj_Type);
      else
         return Null_Iir;
      end if;
   end Get_Resolver;

   --  Return TRUE iff the actual of ASSOC can be the formal.
   --  ASSOC must be an association_element_by_expression.
   function Can_Collapse_Signals (Assoc : Iir; Formal : Iir) return Boolean
   is
      Actual : Iir;
      Actual_Res : Iir;
      Formal_Res : Iir;
      Formal_Base : Iir;
      Actual_Base : Iir;
   begin
      --  If there is a conversion, signals types are not necessarily
      --  the same, and sharing is not possible.
      --  FIXME: optimize type conversions
      --    (unsigned <-> signed <-> std_ulogic_vector <-> ...)
      if Get_Actual_Conversion (Assoc) /= Null_Iir
        or else Get_Formal_Conversion (Assoc) /= Null_Iir
      then
         return False;
      end if;

      --  Here we may assume formal and actual have the same type and the
      --  same lengths.  This is caught at elaboration time.

      Actual := Name_To_Object (Get_Actual (Assoc));
      if Actual = Null_Iir then
         --  This is an expression.
         return False;
      end if;

      Formal_Base := Get_Object_Prefix (Formal);
      Actual_Base := Get_Object_Prefix (Actual);

      if Get_Kind (Formal_Base) = Iir_Kind_Interface_View_Declaration then
         return True;
      end if;

      --  If the formal is of mode IN, then it has no driving value, and its
      --  effective value is the effective value of the actual.
      --  Always collapse in this case.
      if Get_Mode (Formal_Base) = Iir_In_Mode then
         return True;
      end if;

      --  Otherwise, these rules are applied:
      --
      --  In this table, E means element, S means signal.
      --                 Er means the element is resolved,
      --                 Sr means the signal is resolved (at the signal level).
      --
      --                            Actual
      --               | E,S   | Er,S  | E,Sr  | Er,Sr |
      --         ------+-------+-------+-------+-------+
      --         E,S   |collap | no(3) | no(3) | no(3) |
      --         ------+-------+-------+-------+-------+
      --         Er,S  | no(1) |if same| no(2) | no(2) |
      --  Formal ------+-------+-------+-------+-------+
      --         E,Sr  | no(1) | no(2) |if same| no(4) |
      --         ------+-------+-------+-------+-------+
      --         Er,Sr | no(1) | no(2) | no(4) |if same|
      --         ------+-------+-------+-------+-------+
      --
      --  Notes: (1): formal may have several sources.
      --         (2): resolver is not the same.
      --         (3): this prevents to catch several sources error in instance.
      --         (4): resolver is not the same, because the types are not the
      --              same.
      --
      --  Furthermore, signals cannot be collapsed if the kind (none, bus or
      --  register) is not the same.
      --
      --  Default value:  default value is the effective value.

      --  Resolution function.
      Actual_Res := Get_Resolver (Actual);
      Formal_Res := Get_Resolver (Formal);

      --  If the resolutions are not the same, signals cannot be collapsed.
      if Actual_Res /= Formal_Res then
         return False;
      end if;

      --  If neither the actual nor the formal is resolved, then collapsing is
      --  possible.
      --  (this is case ES/ES).
      if Actual_Res = Null_Iir and Formal_Res = Null_Iir then
         return True;
      end if;

      --  If the formal can have sources and is guarded, but the actual is
      --  not guarded (or has not the same kind of guard), signals cannot
      --  be collapsed.
      if (Get_Guarded_Signal_Flag (Formal_Base)
            /= Get_Guarded_Signal_Flag (Actual_Base))
        or else (Get_Signal_Kind (Formal_Base)
                   /= Get_Signal_Kind (Actual_Base))
      then
         return False;
      end if;

      return True;
   end Can_Collapse_Signals;

   --  INTER_PARENT contains generics interfaces;
   --  ASSOC_PARENT contains generic aspects.
   function Sem_Generic_Association_Chain
     (Inter_Parent : Iir; Assoc_Parent : Iir) return Boolean
   is
      El : Iir;
      Match : Compatibility_Level;
      Assoc_Chain : Iir;
      Inter_Chain : Iir;
      Miss : Missing_Type;
   begin
      --  LRM08 6.5.6.2 Generic clauses
      --  If no such actual is specified for a given formal generic constant
      --  (either because the formal generic is unassociated or because the
      --  actual is open), and if a default expression is specified for that
      --  generic, the value of this expression is the value of the generic.
      --  It is an error if no actual is specified for a given formal generic
      --  constant and no default expression is present in the corresponding
      --  interface element.

      --  Note: CHECK_MATCH argument of sem_subprogram_arguments must be
      --   true if parent is a component instantiation.
      case Get_Kind (Assoc_Parent) is
         when Iir_Kind_Component_Instantiation_Statement =>
            --  LRM 9.6 Component Instantiation Statement
            --  Each local generic (or subelement or slice thereof) must be
            --  associated {VHDL87: exactly}{VHDL93: at most} once.
            --  ...
            --  Each local port (or subelement or slice therof) must be
            --  associated {VHDL87: exactly}{VHDL93: at most} once.

            --  GHDL: for a direct instantiation, follow rules of
            --  LRM 1.1.1.1 Generic and LRM 1.1.1.2 Ports.
            --  The difference between 87 and 93 is simply a clarification:
            --  missing association are left open, but need a default
            --  expression in the formal declaration.
            Miss := Missing_Generic;
         when Iir_Kind_Binding_Indication =>
            --  LRM 5.2.1.2  Generic map and port map aspects
            Miss := Missing_Allowed;
         when Iir_Kind_Block_Header =>
            Miss := Missing_Generic;
         when Iir_Kind_Procedure_Instantiation_Declaration
            | Iir_Kind_Function_Instantiation_Declaration =>
            --  LRM08 4.4
            --  Each formal generic (or member thereof) shall be associated
            --  at most once.
            Miss := Missing_Generic;
         when Iir_Kind_Package_Instantiation_Declaration
            | Iir_Kind_Interface_Package_Declaration
            | Iir_Kind_Package_Header =>
            --  LRM08 4.9
            --  Each formal generic (or member thereof) shall be associated
            --  at most once.
            Miss := Missing_Generic;
         when others =>
            Error_Kind ("sem_generic_association_list", Assoc_Parent);
      end case;

      --  The generics
      Inter_Chain := Get_Generic_Chain (Inter_Parent);
      Assoc_Chain := Get_Generic_Map_Aspect_Chain (Assoc_Parent);

      --  Extract non-object associations, as the actual cannot be analyzed
      --  as an expression.
      Assoc_Chain := Extract_Non_Object_Association (Assoc_Chain, Inter_Chain);
      Set_Generic_Map_Aspect_Chain (Assoc_Parent, Assoc_Chain);

      if not Sem_Actual_Of_Association_Chain (Assoc_Chain) then
         return False;
      end if;

      Sem_Association_Chain
        (Inter_Chain, Assoc_Chain, True, Miss, Assoc_Parent, Match);

      --  Clear associated type of interface type.
      --  Should be part of Sem_Association_Chain, but needed only for
      --  generics.
      Clear_Interface_Associated (Inter_Chain);

      Set_Generic_Map_Aspect_Chain (Assoc_Parent, Assoc_Chain);
      if Match = Not_Compatible then
         return False;
      end if;

      --  LRM 5.2.1.2   Generic map and port map aspects
      --  An actual associated with a formal generic map aspect must be an
      --  expression or the reserved word open;
      El := Assoc_Chain;
      while El /= Null_Iir loop
         case Get_Kind (El) is
            when Iir_Kind_Association_Element_By_Expression =>
               Check_Read (Get_Actual (El));
            when Iir_Kind_Association_Element_Open
              | Iir_Kind_Association_Element_By_Individual
              | Iir_Kind_Association_Element_Package
              | Iir_Kind_Association_Element_Type
              | Iir_Kind_Association_Element_Subprogram =>
               null;
            when others =>
               Error_Kind ("sem_generic_association_chain(1)", El);
         end case;
         El := Get_Chain (El);
      end loop;

      return True;
   end Sem_Generic_Association_Chain;

   procedure Sem_Generic_Association_Chain
     (Inter_Parent : Iir; Assoc_Parent : Iir)
   is
      Res : Boolean;
      pragma Unreferenced (Res);
   begin
      Res := Sem_Generic_Association_Chain (Inter_Parent, Assoc_Parent);
   end Sem_Generic_Association_Chain;

   function Sem_Signal_Port_Association
     (Assoc : Iir; Formal : Iir; Formal_Base : Iir) return Iir
   is
      Actual : Iir;
      N_Assoc : Iir;
      Prefix : Iir;
      Object : Iir;
   begin
      Actual := Get_Actual (Assoc);
      --  There has been an error, return now.
      if Actual = Null_Iir then
         return Assoc;
      end if;
      Object := Name_To_Object (Actual);

      if Is_Valid (Object) and then Is_Signal_Object (Object) then
         --  Port or signal.

         --  Mutate to By_Name.
         N_Assoc := Create_Iir (Iir_Kind_Association_Element_By_Name);
         Location_Copy (N_Assoc, Assoc);
         Set_Formal (N_Assoc, Get_Formal (Assoc));
         Set_Chain (N_Assoc, Get_Chain (Assoc));
         Set_Actual (N_Assoc, Actual);
         Set_Actual_Conversion (N_Assoc, Get_Actual_Conversion (Assoc));
         Set_Formal_Conversion (N_Assoc, Get_Formal_Conversion (Assoc));
         Set_Whole_Association_Flag
           (N_Assoc, Get_Whole_Association_Flag (Assoc));
         pragma Assert (not Get_In_Formal_Flag (Assoc));
         if Flag_Elocations then
            declare
               use Vhdl.Elocations;
            begin
               Create_Elocations (N_Assoc);
               Set_Arrow_Location (N_Assoc, Get_Arrow_Location (Assoc));
            end;
         end if;
         Free_Iir (Assoc);

         Set_Collapse_Signal_Flag
           (N_Assoc, Can_Collapse_Signals (N_Assoc, Formal));
         if Get_Name_Staticness (Object) < Globally then
            Error_Msg_Sem (+Actual, "actual must be a static name");
         end if;
         Check_Port_Association_Bounds_Restrictions
           (Formal, Actual, N_Assoc);
         Prefix := Get_Object_Prefix (Object);
         case Get_Kind (Prefix) is
            when Iir_Kind_Interface_Signal_Declaration =>
               declare
                  P : Boolean;
                  pragma Unreferenced (P);
               begin
                  P := Check_Port_Association_Mode_Restrictions
                    (Formal_Base, Prefix, N_Assoc);
               end;
            when Iir_Kind_Signal_Declaration =>
               Set_Use_Flag (Prefix, True);
            when others =>
               --  FIXME: attributes ?
               null;
         end case;
         return N_Assoc;
      else
         --  Expression.
         Set_Collapse_Signal_Flag (Assoc, False);

         pragma Assert (Is_Null (Get_Actual_Conversion (Assoc)));
         if Flags.Vhdl_Std >= Vhdl_93 then
            --  LRM93 1.1.1.2 Ports
            --  Moreover, the ports of a block may be associated
            --  with an expression, in order to provide these ports
            --  with constant driving values; such ports must be
            --  of mode in.
            if Get_Mode (Formal_Base) /= Iir_In_Mode then
               Error_Msg_Sem
                 (+Assoc, "only 'in' ports may be associated with expression");
            end if;

            --  Is it possible to have a globally static name that is
            --  not readable ?
            Check_Read (Actual);

            --  LRM93 1.1.1.2 Ports
            --  The actual, if an expression, must be a globally
            --  static expression.
            if Get_Expr_Staticness (Actual) < Globally then
               --  This is an inertial association.
               Set_Inertial_Flag (Assoc, True);

               if Flags.Vhdl_Std < Vhdl_08 then
                  --  LRM08 6.5.6.3 Port clauses
                  Error_Msg_Sem
                    (+Actual, "actual expression must be globally static");
               end if;
            end if;
         else
            Error_Msg_Sem
              (+Assoc, "cannot associate ports with expression in vhdl87");
         end if;
         return Assoc;
      end if;
   end Sem_Signal_Port_Association;

   --  INTER_PARENT contains ports interfaces;
   --  ASSOC_PARENT constains ports map aspects.
   procedure Sem_Port_Association_Chain
     (Inter_Parent : Iir; Assoc_Parent : Iir)
   is
      Assoc : Iir;
      Prev_Assoc, N_Assoc : Iir;
      Match : Compatibility_Level;
      Assoc_Chain : Iir;
      Inter_Chain : Iir;
      Miss : Missing_Type;
      Inter : Iir;
      Formal : Iir;
      Formal_Base : Iir;
   begin
      --  Note: CHECK_MATCH argument of sem_subprogram_arguments must be
      --   true if parent is a component instantiation.
      case Get_Kind (Assoc_Parent) is
         when Iir_Kind_Component_Instantiation_Statement =>
            --  LRM 9.6 Component Instantiation Statement
            --  Each local generic (or subelement or slice thereof) must be
            --  associated {VHDL87: exactly}{VHDL93: at most} once.
            --  ...
            --  Each local port (or subelement or slice therof) must be
            --  associated {VHDL87: exactly}{VHDL93: at most} once.

            --  GHDL: for a direct instantiation, follow rules of
            --  LRM 1.1.1.1 Generic and LRM 1.1.1.2 Ports.
            Miss := Missing_Port;
         when Iir_Kind_Binding_Indication =>
            --  LRM 5.2.1.2  Generic map and port map aspects
            Miss := Missing_Allowed;
         when Iir_Kind_Block_Header =>
            --  FIXME: it is possible to have port unassociated ?
            Miss := Missing_Port;
         when others =>
            Error_Kind ("sem_port_association_chain", Assoc_Parent);
      end case;

      --  The ports
      Assoc_Chain := Get_Port_Map_Aspect_Chain (Assoc_Parent);
      Inter_Chain := Get_Port_Chain (Inter_Parent);

      if AMS_Vhdl then
         --  Mutate terminal associations, so that their formals are not
         --  analyzed as an expression.
         Assoc_Chain :=
           Extract_Non_Object_Association (Assoc_Chain, Inter_Chain);
      end if;

      if not Sem_Actual_Of_Association_Chain (Assoc_Chain) then
         return;
      end if;
      Sem_Association_Chain (Inter_Chain, Assoc_Chain,
                             True, Miss, Assoc_Parent, Match);
      Set_Port_Map_Aspect_Chain (Assoc_Parent, Assoc_Chain);
      if Match = Not_Compatible then
         --  TODO: mark actual as used to avoid warnings.
         return;
      end if;

      --  LRM 5.2.1.2  Generic map and port map aspects
      --  [...]; an actual associated with a formal port in a port map aspect
      --  must be a signal, an expression, or the reserved word open.
      --
      --  Certain restriction apply to the actual associated with a formal in
      --  a port map aspect; these restrictions are described in 1.1.1.2

      --  LRM93 1.1.1.2
      --  The actual, if a port or signal, must be denoted by a static name.
      --  The actual, if an expression, must be a globally static expression.
      Assoc := Assoc_Chain;
      Inter := Get_Port_Chain (Inter_Parent);
      Prev_Assoc := Null_Iir;
      while Assoc /= Null_Iir loop
         Formal := Get_Association_Formal (Assoc, Inter);
         Formal_Base := Get_Interface_Of_Formal (Formal);

         case Get_Kind (Formal_Base) is
            when Iir_Kind_Interface_Signal_Declaration
               | Iir_Kind_Interface_View_Declaration =>
               if Get_Kind (Assoc) = Iir_Kind_Association_Element_By_Expression
               then
                  N_Assoc := Sem_Signal_Port_Association
                    (Assoc, Formal, Formal_Base);

                  --  Reinsert the new association (in case of mutation).
                  if N_Assoc /= Assoc then
                     if Prev_Assoc /= Null_Iir then
                        Set_Chain (Prev_Assoc, N_Assoc);
                     else
                        Set_Port_Map_Aspect_Chain (Assoc_Parent, N_Assoc);
                     end if;
                     Assoc := N_Assoc;
                  end if;
               end if;
            when others =>
               null;
         end case;

         Prev_Assoc := Assoc;
         Next_Association_Interface (Assoc, Inter);
      end loop;
   end Sem_Port_Association_Chain;

   --  LRM 1.3  Configuration Declarations.
   procedure Sem_Configuration_Declaration (Decl: Iir)
   is
      Entity: Iir_Entity_Declaration;
      Entity_Unit : Iir_Design_Unit;
   begin
      Xref_Decl (Decl);
      Set_Is_Within_Flag (Decl, True);

      --  LRM 1.3
      --  The entity name identifies the name of the entity declaration that
      --  defines the design entity at the apex of the design hierarchy.
      Entity := Sem_Entity_Name (Decl);
      if Entity = Null_Iir then
         return;
      end if;
      Entity_Unit := Get_Design_Unit (Entity);

      --  LRM 11.4
      --  A primary unit whose name is referenced within a given design unit
      --  must be analyzed prior to the analysis of the given design unit.
      Add_Dependence (Entity_Unit);

      Sem_Scopes.Add_Name (Decl);

      Set_Visible_Flag (Decl, True);

      --  LRM 10.1 Declarative Region
      --  2.  A configuration declaration.
      Open_Declarative_Region;

      --  LRM93 10.2
      --  In addition to the above rules, the scope of any declaration that
      --  includes the end of the declarative part of a given block (whether
      --  it be an external block defined by a design entity or an internal
      --  block defined by a block statement) extends into a configuration
      --  declaration that configures the given block.
      Add_Context_Clauses (Entity_Unit);
      Sem_Scopes.Add_Entity_Declarations (Entity);

      Sem_Declaration_Chain (Decl);
      --  GHDL: no need to check for missing subprogram bodies, since they are
      --  not allowed in configuration declarations.

      Sem_Block_Configuration (Get_Block_Configuration (Decl), Decl);
      Close_Declarative_Region;
      Set_Is_Within_Flag (Decl, False);
   end Sem_Configuration_Declaration;

   --  Analyze the block specification of a block statement or of a generate
   --  statement.  Return the corresponding block statement, generate
   --  statement body, or Null_Iir in case of error.
   function Sem_Block_Specification_Of_Statement
     (Block_Conf : Iir_Block_Configuration; Father : Iir) return Iir
   is
      Block_Spec : Iir;
      Block_Name : Iir;
      Block_Stmts : Iir;
      Prev : Iir_Block_Configuration;
      Block : Iir;
      Res : Iir;
      Assoc : Iir;
      Clause : Iir;
      Gen_Spec : Iir;
   begin
      Block_Spec := Get_Block_Specification (Block_Conf);
      case Get_Kind (Block_Spec) is
         when Iir_Kind_Simple_Name =>
            Block_Name := Block_Spec;
         when Iir_Kind_Parenthesis_Name
           | Iir_Kind_Slice_Name =>
            Block_Name := Get_Prefix (Block_Spec);
         when others =>
            Error_Msg_Sem (+Block_Spec, "label expected");
            return Null_Iir;
      end case;

      --  Analyze the label and generate specification.
      Block_Name := Sem_Denoting_Name (Block_Name);
      Block := Get_Named_Entity (Block_Name);
      case Get_Kind (Block) is
         when Iir_Kind_Block_Statement =>
            if Get_Kind (Block_Spec) /= Iir_Kind_Simple_Name then
               Error_Msg_Sem (+Block_Spec,
                              "label does not denote a generate statement");
            end if;
            Set_Block_Specification (Block_Conf, Block_Name);
            Prev := Get_Block_Block_Configuration (Block);
            Res := Block;

         when Iir_Kind_For_Generate_Statement =>
            Res := Get_Generate_Statement_Body (Block);
            Set_Named_Entity (Block_Name, Res);
            Prev := Get_Generate_Block_Configuration (Res);

            case Get_Kind (Block_Spec) is
               when Iir_Kind_Simple_Name =>
                  Set_Block_Specification (Block_Conf, Block_Name);
               when Iir_Kind_Parenthesis_Name =>
                  Block_Spec := Sem_Index_Specification
                    (Block_Spec,
                     Get_Type (Get_Parameter_Specification (Block)));
                  if Block_Spec /= Null_Iir then
                     Set_Prefix (Block_Spec, Block_Name);
                     Set_Block_Specification (Block_Conf, Block_Spec);
                  end if;
               when others =>
                  raise Internal_Error;
            end case;

         when Iir_Kind_If_Generate_Statement =>
            case Get_Kind (Block_Spec) is
               when Iir_Kind_Simple_Name =>
                  --  LRM08 3.4.2 Block configuration
                  --  If no generate specification appears in such a block
                  --  configuration, then it applies to exactly one of the
                  --  following sets of blocks:
                  --  [...]
                  --  - The implicit block generated by the corresponding
                  --    generate statement, if and only if the corresponding
                  --    generate is an if generate statement and if the first
                  --    condition after IF evaluates to TRUE.
                  Res := Get_Generate_Statement_Body (Block);

                  --  LRM08 3.4.2 Block configuration
                  --  If the block specification of a block configuration
                  --  contains a generate statement label that denotes an if
                  --  generate statement, and if the first condition after IF
                  --  has an alternative label, then it is an error if the
                  --  generate statement label does not contain a generate
                  --  specification that is an alternative label.
                  if Has_User_Label (Res) then
                     Error_Msg_Sem
                       (+Block_Spec,
                        "alternative label required in block specification");
                  end if;

                  Set_Block_Specification (Block_Conf, Block_Name);

               when Iir_Kind_Parenthesis_Name =>
                  if Vhdl_Std < Vhdl_08 then
                     Error_Msg_Sem
                       (+Block_Spec,
                        "alternative label only allowed by vhdl08");
                     return Null_Iir;
                  end if;
                  Assoc := Get_Association_Chain (Block_Spec);
                  pragma Assert
                    (Get_Kind (Assoc)
                       = Iir_Kind_Association_Element_By_Expression);
                  Gen_Spec := Get_Actual (Assoc);
                  if Get_Kind (Gen_Spec) /= Iir_Kind_Simple_Name then
                     Error_Msg_Sem
                       (+Gen_Spec,
                        "alternative label expected for if-generate");
                     return Null_Iir;
                  end if;
                  --  Search label.
                  Clause := Block;
                  while Clause /= Null_Iir loop
                     Res := Get_Generate_Statement_Body (Clause);
                     exit when Get_Alternative_Label (Res)
                       = Get_Identifier (Gen_Spec);
                     Clause := Get_Generate_Else_Clause (Clause);
                  end loop;
                  if Clause = Null_Iir then
                     Error_Msg_Sem
                       (+Gen_Spec,
                        "alternative label %i not found for if-generate",
                        +Gen_Spec);
                     return Null_Iir;
                  end if;
                  Set_Named_Entity (Block_Spec, Res);
                  Xref_Ref (Gen_Spec, Res);
                  Set_Prefix (Block_Spec, Block_Name);
                  Set_Block_Specification (Block_Conf, Block_Spec);

               when others =>
                  raise Internal_Error;
            end case;

            Set_Named_Entity (Block_Name, Res);
            Prev := Get_Generate_Block_Configuration (Res);

         when Iir_Kind_Case_Generate_Statement =>
            case Get_Kind (Block_Spec) is
               when Iir_Kind_Simple_Name =>
                  --  LRM08 3.4.2 Block configuration
                  --  If no generate specification appears in such a block
                  --  configuration, [...]
                  --  GHDL: doesn't apply to case generate statement
                  Error_Msg_Sem
                    (+Block_Spec,
                     "missing alternative label for a case-generate");
                  return Null_Iir;
               when Iir_Kind_Parenthesis_Name =>
                  Assoc := Get_Association_Chain (Block_Spec);
                  pragma Assert
                    (Get_Kind (Assoc)
                       = Iir_Kind_Association_Element_By_Expression);
                  Gen_Spec := Get_Actual (Assoc);
                  if Get_Kind (Gen_Spec) /= Iir_Kind_Simple_Name then
                     Error_Msg_Sem
                       (+Gen_Spec,
                        "alternative label expected for case-generate");
                     return Null_Iir;
                  end if;
                  --  Search label.
                  Clause := Get_Case_Statement_Alternative_Chain (Block);
                  while Clause /= Null_Iir loop
                     Res := Get_Associated_Block (Clause);
                     exit when Get_Alternative_Label (Res)
                       = Get_Identifier (Gen_Spec);
                     Clause := Get_Chain (Clause);
                  end loop;
                  if Clause = Null_Iir then
                     Error_Msg_Sem
                       (+Gen_Spec,
                        "alternative label %i not found for case-generate",
                        +Gen_Spec);
                     return Null_Iir;
                  end if;
                  Set_Named_Entity (Block_Spec, Res);
                  Xref_Ref (Gen_Spec, Res);
                  Set_Prefix (Block_Spec, Block_Name);
                  Set_Block_Specification (Block_Conf, Block_Spec);

               when others =>
                  raise Internal_Error;
            end case;

            Set_Named_Entity (Block_Name, Res);
            Prev := Get_Generate_Block_Configuration (Res);

         when others =>
            Error_Msg_Sem (+Block_Conf,
                           "block or generate statement label expected");
            return Null_Iir;
      end case;

      --  LRM93 1.3.1 / LRM08 3.4.2 Block configuration
      --  [...], and the label must denote a block statement or generate
      --  statement that is contained immediatly within the block denoted by
      --  the block specification of the containing block configuration.
      Block_Stmts := Get_Concurrent_Statement_Chain
        (Get_Block_From_Block_Specification
           (Get_Block_Specification (Father)));
      if not Is_In_Chain (Block_Stmts, Block) then
         Error_Msg_Sem (+Block_Conf,
                        "label does not denotes an inner block statement");
         return Null_Iir;
      end if;

      case Get_Kind (Block) is
         when Iir_Kind_Block_Statement =>
            --  LRM93 1.3
            --  It is an error if, in a given block configuration, more than
            --  one configuration item is defined for the same block [or
            --  component instance].
            if Prev /= Null_Iir then
               Error_Msg_Sem
                 (+Block_Conf,
                  "%n was already configured at %l", (+Block, +Prev));
               return Null_Iir;
            end if;
            Set_Block_Block_Configuration (Res, Block_Conf);

         when Iir_Kind_If_Generate_Statement
           | Iir_Kind_Case_Generate_Statement =>
            --  LRM93 1.3
            --  It is an error if, in a given block configuration, more than
            --  one configuration item is defined for the same block [or
            --  component instance].
            if Prev /= Null_Iir then
               Error_Msg_Sem
                 (+Block_Conf,
                  "%n was already configured at %l", (+Block, +Prev));
               return Null_Iir;
            end if;
            Set_Generate_Block_Configuration (Res, Block_Conf);

         when Iir_Kind_For_Generate_Statement =>
            --  LRM93 1.3
            --  For any name that is the label of a generate statement
            --  immediately wihin a given block, one or more corresponding
            --  block configuration may appear as configuration items
            --  immediately within a block configuration corresponding to the
            --  given block.
            --  GHDL: keep them in a linked list, but don't try to detect
            --  duplicate as values may not be static.  FIXME: try for
            --  static values only ?
            Set_Prev_Block_Configuration (Block_Conf, Prev);
            Set_Generate_Block_Configuration (Res, Block_Conf);
         when others =>
            raise Internal_Error;
      end case;
      return Res;
   end Sem_Block_Specification_Of_Statement;

   --  LRM 1.3.1  Block Configuration.
   --  FATHER is the block_configuration, configuration_declaration,
   --  component_configuration containing the block_configuration BLOCK_CONF.
   procedure Sem_Block_Configuration
     (Block_Conf : Iir_Block_Configuration; Father: Iir)
   is
      El : Iir;
      Block : Iir;
   begin
      case Get_Kind (Father) is
         when Iir_Kind_Configuration_Declaration =>
            --  LRM93 1.3.1
            --  If a block configuration appears immediately within a
            --  configuration declaration, then the block specification of that
            --  block configuration must be an architecture name, and that
            --  architecture name must denote a design entity body whose
            --  interface is defined by the entity declaration denoted by the
            --  entity name of the enclosing configuration declaration.
            declare
               Block_Spec : Iir;
               Arch : Iir_Architecture_Body;
               Design: Iir_Design_Unit;
            begin
               Block_Spec := Get_Block_Specification (Block_Conf);
               --  FIXME: handle selected name.
               if Get_Kind (Block_Spec) /= Iir_Kind_Simple_Name then
                  Error_Msg_Sem (+Block_Spec, "architecture name expected");
                  return;
               end if;
               --  LRM 10.3 rule b)
               --  For an architecture body associated with a given entity
               --  declaration: at the place of the block specification in a
               --  block configuration for an external block whose interface
               --  is defined by that entity declaration.
               Design := Load_Secondary_Unit
                 (Get_Design_Unit (Get_Entity (Father)),
                  Get_Identifier (Block_Spec),
                  Block_Conf);
               if Design = Null_Iir then
                  Error_Msg_Sem
                    (+Block_Conf, "no architecture %i", +Block_Spec);
                  return;
               end if;
               Arch := Get_Library_Unit (Design);
               Set_Named_Entity (Block_Spec, Arch);
               Xref_Ref (Block_Spec, Arch);
               Block := Arch;
               Add_Dependence (Design);
            end;

         when Iir_Kind_Component_Configuration =>
            --  LRM93 1.3.1
            --  If a block configuration appears immediately within a component
            --  configuration, then the corresponding components must be
            --  fully bound, the block specification of that block
            --  configuration must be an architecture name, and that
            --  architecture name must denote the same architecture body as
            --  that to which the corresponding components are bound.
            declare
               Block_Spec : Iir;
               Arch : Iir_Architecture_Body;
               Design: Iir_Design_Unit;
               Entity_Aspect : Iir;
               Entity : Iir;
               Comp_Arch : Iir;
            begin
               Entity_Aspect :=
                 Get_Entity_Aspect (Get_Binding_Indication (Father));
               if Entity_Aspect = Null_Iir or else
                 Get_Kind (Entity_Aspect) /= Iir_Kind_Entity_Aspect_Entity
               then
                  Error_Msg_Sem
                    (+Block_Conf, "corresponding component not fully bound");
                  return;
               end if;

               Block_Spec := Get_Block_Specification (Block_Conf);
               --  FIXME: handle selected name.
               if Get_Kind (Block_Spec) /= Iir_Kind_Simple_Name then
                  Error_Msg_Sem (+Block_Spec, "architecture name expected");
                  return;
               end if;

               Comp_Arch := Get_Architecture (Entity_Aspect);
               if Comp_Arch /= Null_Iir then
                  pragma Assert (Get_Kind (Comp_Arch) = Iir_Kind_Simple_Name);
                  if Get_Identifier (Comp_Arch) /= Get_Identifier (Block_Spec)
                  then
                     Error_Msg_Sem
                       (+Block_Spec, "block specification name is different "
                          & "from component architecture name");
                     return;
                  end if;
               end if;

               Entity := Get_Entity (Entity_Aspect);
               if Entity = Null_Iir then
                  return;
               end if;

               Design := Load_Secondary_Unit (Get_Design_Unit (Entity),
                                              Get_Identifier (Block_Spec),
                                              Block_Conf);
               if Design = Null_Iir then
                  Error_Msg_Sem
                    (+Block_Conf, "no architecture %i", +Block_Spec);
                  return;
               end if;
               Add_Dependence (Design);
               Arch := Get_Library_Unit (Design);
               Set_Named_Entity (Block_Spec, Arch);
               Xref_Ref (Block_Spec, Arch);
               Block := Arch;
            end;

         when Iir_Kind_Block_Configuration =>
            --  LRM93 1.3.1 / LRM08 3.4.2 Block configuration
            --  If a block configuration appears immediately within another
            --  block configuration, then the block specification of the
            --  contained block configuration must be a block statement or
            --  generate statement label, and the label must denote a block
            --  statement or generate statement that is contained immediatly
            --  within the block denoted by the block specification of the
            --  containing block configuration.
            Block := Sem_Block_Specification_Of_Statement (Block_Conf, Father);
            if Block = Null_Iir then
               return;
            end if;

         when others =>
            Error_Kind ("sem_block_configuration", Father);
      end case;

      --  LRM93 10.1
      --  10. A block configuration
      Sem_Scopes.Open_Scope_Extension;

      --  LRM 10.3
      --  In addition, any declaration that is directly visible at the end of
      --  the declarative part of a given block is directly visible in a block
      --  configuration that configure the given block.  This rule holds unless
      --  a use clause that makes a homograph of the declaration potentially
      --  visible (see 10.4) appears in the corresponding configuration
      --  declaration, and if the scope of that use clause encompasses all or
      --  part of those configuration items.  If such a use clause appears,
      --  then the declaration will be directly visible within the
      --  corresponding configuration items, except at hose places that fall
      --  within the scope of the additional use clause.  At such places,
      --  neither name will be directly visible.
      --  FIXME: handle use clauses.
      Sem_Scopes.Extend_Scope_Of_Block_Declarations (Block);

      declare
         El : Iir;
      begin
         El := Get_Declaration_Chain (Block_Conf);
         while El /= Null_Iir loop
            case Get_Kind (El) is
               when Iir_Kind_Use_Clause =>
                  Sem_Use_Clause (El);
               when others =>
                  --  Parse checks there are only use clauses.
                  raise Internal_Error;
            end case;
            El := Get_Chain (El);
         end loop;
      end;

      --  VHDL 87: do not remove configuration specification in generate stmts.
      Clear_Instantiation_Configuration (Block);

      El := Get_Configuration_Item_Chain (Block_Conf);
      while El /= Null_Iir loop
         case Get_Kind (El) is
            when Iir_Kind_Block_Configuration =>
               Sem_Block_Configuration (El, Block_Conf);
            when Iir_Kind_Component_Configuration =>
               Sem_Component_Configuration (El, Block_Conf);
            when others =>
               Error_Kind ("sem_block_configuration(2)", El);
         end case;
         El := Get_Chain (El);
      end loop;
      Sem_Scopes.Close_Scope_Extension;
   end Sem_Block_Configuration;

   --  Check that incremental binding of the component configuration CONF only
   --  rebinds non associated ports of each instantiations of CONFIGURED_BLOCK
   --  which CONF applies to.
   procedure Check_Incremental_Binding (Configured_Block : Iir; Conf : Iir)
   is
      Comp : constant Iir := Get_Named_Entity (Get_Component_Name (Conf));
      Inter_Chain : constant Iir := Get_Port_Chain (Comp);
      Binding : constant Iir := Get_Binding_Indication (Conf);
      Inst : Iir;
   begin
      --  Check each component instantiation of the block configured by CONF.
      Inst := Get_Concurrent_Statement_Chain (Configured_Block);
      while Inst /= Null_Iir loop
         if Get_Kind (Inst) = Iir_Kind_Component_Instantiation_Statement
           and then Get_Component_Configuration (Inst) = Conf
         then
            --  Check this instantiation.
            declare
               Primary_Binding : constant Iir := Get_Binding_Indication
                 (Get_Configuration_Specification (Inst));
               F_Chain : constant Iir :=
                 Get_Port_Map_Aspect_Chain (Primary_Binding);
               S_El : Iir;
               S_Inter : Iir;
               F_El : Iir;
               Formal : Iir;
            begin
               S_El := Get_Port_Map_Aspect_Chain (Binding);
               S_Inter := Inter_Chain;
               while S_El /= Null_Iir loop
                  --  Find S_EL formal in F_CHAIN.
                  Formal := Get_Association_Interface (S_El, S_Inter);
                  F_El := Find_First_Association_For_Interface
                    (F_Chain, Inter_Chain, Formal);
                  if F_El /= Null_Iir
                    and then
                    Get_Kind (F_El) /= Iir_Kind_Association_Element_Open
                  then
                     Error_Msg_Sem
                       (+S_El,
                        "%n already associated in primary binding", +Formal);
                  end if;
                  Next_Association_Interface (S_El, S_Inter);
               end loop;
            end;
         end if;
         Inst := Get_Chain (Inst);
      end loop;
   end Check_Incremental_Binding;

   --  LRM 1.3.2
   procedure Sem_Component_Configuration
     (Conf : Iir_Component_Configuration; Father : Iir)
   is
      Block : Iir;
      Configured_Block : Iir;
      Binding : Iir;
      Entity : Iir_Design_Unit;
      Comp : Iir_Component_Declaration;
      Primary_Binding : Iir;
   begin
      --  LRM 10.1 Declarative Region
      --  11. A component configuration.
      Open_Declarative_Region;

      --  LRM93 10.2
      --  If a component configuration appears as a configuration item
      --  immediatly within a block configuration that configures a given
      --  block, and the scope of a given declaration includes the end of the
      --  declarative part of that block, then the scope of the given
      --  declaration extends from the beginning to the end of the
      --  declarative region associated with the given component configuration.
      -- GHDL: this is for labels of component instantiation statements, and
      -- for local ports and generics of the component.
      if Get_Kind (Father) = Iir_Kind_Block_Configuration then
         Configured_Block := Get_Block_Specification (Father);
         pragma Assert (Get_Kind (Configured_Block) /= Iir_Kind_Design_Unit);
         Configured_Block :=
           Get_Block_From_Block_Specification (Configured_Block);
         Sem_Scopes.Extend_Scope_Of_Block_Declarations (Configured_Block);
      else
         --  Can a component configuration not be just inside a block
         --  configuration ?
         raise Internal_Error;
      end if;
      --  FIXME: this is wrong (all declarations should be considered).
      Sem_Component_Specification
        (Configured_Block, Conf, Primary_Binding);

      Comp := Get_Named_Entity (Get_Component_Name (Conf));
      if Get_Kind (Comp) /= Iir_Kind_Component_Declaration then
         --  There has been an error in sem_component_specification.
         --  Leave here.
         Close_Declarative_Region;
         return;
      end if;

      --  FIXME: (todo)
      --  If a given component instance is unbound in the corresponding block,
      --  then any explicit component configuration for that instance that does
      --  not contain an explicit binding indication will contain an implicit,
      --  default binding indication (see 5.2.2).  Similarly, if a given
      --  component instance is unbound in the corresponding block, then any
      --  implicit component configuration for that instance will contain an
      --  implicit, default binding indication.
      Open_Declarative_Region;
      Sem_Scopes.Add_Component_Declarations (Comp);
      Binding := Get_Binding_Indication (Conf);
      if Binding /= Null_Iir then
         Sem_Binding_Indication (Binding, Conf, Primary_Binding);

         if Primary_Binding /= Null_Iir then
            --  LRM93 5.2.1  Binding Indication
            --  It is an error if a formal port appears in the port map aspect
            --  of the incremental binding indication and it is a formal
            --  port that is associated with an actual other than OPEN in one
            --  of the primary binding indications.
            Check_Incremental_Binding (Configured_Block, Conf);
         end if;
      elsif Primary_Binding = Null_Iir then
         --  LRM93 5.2.1
         --  If the generic map aspect or port map aspect of a primary binding
         --  indication is not present, then the default rules as described
         --  in 5.2.2 apply.

         --  Create a default binding indication.
         Entity := Get_Visible_Entity_Declaration (Comp);
         Binding := Sem_Create_Default_Binding_Indication
           (Comp, Entity, Conf, False, False);

         if Binding /= Null_Iir then
            --  Remap to defaults.
            Set_Default_Entity_Aspect (Binding, Get_Entity_Aspect (Binding));
            Set_Entity_Aspect (Binding, Null_Iir);

            Set_Binding_Indication (Conf, Binding);
         end if;
      end if;
      Close_Declarative_Region;

      --  External block.
      Block := Get_Block_Configuration (Conf);
      if Block /= Null_Iir and then Binding /= Null_Iir then
         Sem_Block_Configuration (Block, Conf);
      end if;
      Close_Declarative_Region;
   end Sem_Component_Configuration;

   function Are_Trees_Chain_Equal (Left, Right : Iir) return Boolean
   is
      El_Left, El_Right : Iir;
   begin
      if Left = Right then
         return True;
      end if;
      El_Left := Left;
      El_Right := Right;
      loop
         if El_Left = Null_Iir and El_Right = Null_Iir then
            return True;
         end if;
         if El_Left = Null_Iir or El_Right = Null_Iir then
            return False;
         end if;
         if not Are_Trees_Equal (El_Left, El_Right) then
            return False;
         end if;
         El_Left := Get_Chain (El_Left);
         El_Right := Get_Chain (El_Right);
      end loop;
   end Are_Trees_Chain_Equal;

   function Are_Trees_List_Equal (Left, Right : Iir_Flist) return Boolean
   is
      El_Left, El_Right : Iir;
   begin
      pragma Assert (Flist_Last (Left) = Flist_Last (Right));
      for I in Flist_First .. Flist_Last (Left) loop
         El_Left := Get_Nth_Element (Left, I);
         El_Right := Get_Nth_Element (Right, I);
         if not Are_Trees_Equal (El_Left, El_Right) then
            return False;
         end if;
      end loop;
      return True;
   end Are_Trees_List_Equal;

   --  Return TRUE iff LEFT and RIGHT are (in depth) equal.
   --  This corresponds to conformance rules, LRM93 2.7
   function Are_Trees_Equal (Left, Right : Iir) return Boolean
   is
      El_Left, El_Right : Iir;
   begin
      --  Short-cut to speed up.
      if Left = Right then
         return True;
      end if;

      --  Handle null_iir.
      if Left = Null_Iir or Right = Null_Iir then
         --  Note: LEFT *xor* RIGHT is null_iir.
         return False;
      end if;

      --  LRM 2.7  Conformance Rules
      --  A simple name can be replaced by an expanded name in which this
      --  simple name is the selector, if and only if at both places the
      --  meaning of the simple name is given by the same declaration.
      if Get_Kind (Left) in Iir_Kinds_Denoting_Name then
         if Get_Kind (Right) in Iir_Kinds_Denoting_Name then
            return Get_Identifier (Left) = Get_Identifier (Right)
              and then Get_Named_Entity (Left) = Get_Named_Entity (Right);
         else
            return False;
         end if;
      end if;

      --  If nodes are not of the same kind, then they are not equals!
      if Get_Kind (Left) /= Get_Kind (Right) then
         return False;
      end if;

      case Get_Kind (Left) is
         when Iir_Kind_Procedure_Declaration =>
            return Are_Trees_Chain_Equal
              (Get_Interface_Declaration_Chain (Left),
               Get_Interface_Declaration_Chain (Right));
         when Iir_Kind_Function_Declaration =>
            if not Are_Trees_Equal (Get_Return_Type (Left),
                                    Get_Return_Type (Right))
            then
               return False;
            end if;
            if Get_Pure_Flag (Left) /= Get_Pure_Flag (Right) then
               return False;
            end if;
            if not Are_Trees_Chain_Equal
              (Get_Interface_Declaration_Chain (Left),
               Get_Interface_Declaration_Chain (Right))
            then
               return False;
            end if;
            return True;
         when Iir_Kind_Interface_Constant_Declaration
           | Iir_Kind_Interface_Variable_Declaration
           | Iir_Kind_Interface_Signal_Declaration
           | Iir_Kind_Interface_File_Declaration =>
            if Get_Identifier (Left) /= Get_Identifier (Right) then
               return False;
            end if;
            if Get_Has_Mode (Left) /= Get_Has_Mode (Right)
              or else Get_Has_Class (Left) /= Get_Has_Class (Right)
              or else (Get_Has_Identifier_List (Left)
                         /= Get_Has_Identifier_List (Right))
              or else Get_Mode (Left) /= Get_Mode (Right)
            then
               return False;
            end if;
            if not Are_Trees_Equal (Get_Subtype_Indication (Left),
                                    Get_Subtype_Indication (Right))
            then
               return False;
            end if;
            El_Left := Get_Default_Value (Left);
            El_Right := Get_Default_Value (Right);
            if (El_Left = Null_Iir) xor (El_Right = Null_Iir)  then
               return False;
            end if;
            if El_Left /= Null_Iir
              and then Are_Trees_Equal (El_Left, El_Right) = False
            then
               return False;
            end if;
            return True;

         when Iir_Kind_Integer_Subtype_Definition
           | Iir_Kind_Enumeration_Subtype_Definition
           | Iir_Kind_Floating_Subtype_Definition
           | Iir_Kind_Physical_Subtype_Definition =>
            if Get_Base_Type (Left) /= Get_Base_Type (Right) then
               return False;
            end if;
            if Get_Type_Declarator (Left) /= Get_Type_Declarator (Right) then
               return False;
            end if;
            if not Are_Trees_Equal (Get_Resolution_Indication (Left),
                                    Get_Resolution_Indication (Right))
            then
               return False;
            end if;
            if Are_Trees_Equal (Get_Range_Constraint (Left),
                                Get_Range_Constraint (Right)) = False
            then
               return False;
            end if;
            return True;
         when Iir_Kind_Array_Subtype_Definition =>
            if Get_Base_Type (Left) /= Get_Base_Type (Right) then
               return False;
            end if;
            if not Are_Trees_Equal (Get_Resolution_Indication (Left),
                                    Get_Resolution_Indication (Right))
            then
               return False;
            end if;
            if not Are_Trees_List_Equal (Get_Index_Subtype_List (Left),
                                         Get_Index_Subtype_List (Right))
            then
               return False;
            end if;
            return True;
         when Iir_Kind_Record_Subtype_Definition =>
            if Get_Base_Type (Left) /= Get_Base_Type (Right) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Resolution_Indication (Left),
                                    Get_Resolution_Indication (Right))
              and then
              Are_Trees_List_Equal (Get_Elements_Declaration_List (Left),
                                    Get_Elements_Declaration_List (Right));
         when Iir_Kind_Record_Element_Constraint =>
            if Get_Identifier (Left) /= Get_Identifier (Right) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Subtype_Indication (Left),
                                    Get_Subtype_Indication (Right));
         when Iir_Kind_Integer_Literal =>
            if Get_Value (Left) /= Get_Value (Right) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Literal_Origin (Left),
                                    Get_Literal_Origin (Right));
         when Iir_Kind_Enumeration_Literal =>
            if Get_Enum_Pos (Left) /= Get_Enum_Pos (Right) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Literal_Origin (Left),
                                    Get_Literal_Origin (Right));
         when Iir_Kind_Physical_Int_Literal =>
            if Get_Value (Left) /= Get_Value (Right)
              or else not Are_Trees_Equal (Get_Unit_Name (Left),
                                           Get_Unit_Name (Right))
            then
               return False;
            end if;
            return Are_Trees_Equal (Get_Literal_Origin (Left),
                                    Get_Literal_Origin (Right));
         when Iir_Kind_Physical_Fp_Literal =>
            if Get_Fp_Value (Left) /= Get_Fp_Value (Right)
              or else not Are_Trees_Equal (Get_Unit_Name (Left),
                                           Get_Unit_Name (Right))
            then
               return False;
            end if;
            return Are_Trees_Equal (Get_Literal_Origin (Left),
                                    Get_Literal_Origin (Right));
         when Iir_Kind_Unit_Declaration =>
            return Left = Right;
         when Iir_Kind_Floating_Point_Literal =>
            if Get_Fp_Value (Left) /= Get_Fp_Value (Right) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Literal_Origin (Left),
                                    Get_Literal_Origin (Right));

         when Iir_Kinds_Dyadic_Operator =>
            return Are_Trees_Equal (Get_Left (Left), Get_Left (Right))
              and then Are_Trees_Equal (Get_Right (Left), Get_Right (Right));
         when Iir_Kinds_Monadic_Operator =>
            return Are_Trees_Equal (Get_Operand (Left), Get_Operand (Right));

         when Iir_Kind_Function_Call =>
            return Are_Trees_Equal (Get_Prefix (Left), Get_Prefix (Right))
              and then
              Are_Trees_Chain_Equal (Get_Parameter_Association_Chain (Left),
                                     Get_Parameter_Association_Chain (Right));

         when Iir_Kind_Association_Element_By_Expression =>
            return Are_Trees_Equal (Get_Actual (Left), Get_Actual (Right))
              and then Are_Trees_Equal (Get_Formal (Left), Get_Formal (Right))
              and then Are_Trees_Equal (Get_Actual_Conversion (Left),
                                        Get_Actual_Conversion (Right))
              and then Are_Trees_Equal (Get_Formal_Conversion (Left),
                                        Get_Formal_Conversion (Right));

         when Iir_Kind_Type_Conversion
           | Iir_Kind_Qualified_Expression =>
            return Are_Trees_Equal (Get_Type_Mark (Left),
                                    Get_Type_Mark (Right))
              and then
              Are_Trees_Equal (Get_Expression (Left),
                               Get_Expression (Right));

         when Iir_Kind_Indexed_Name =>
            return Are_Trees_Equal (Get_Prefix (Left),
                                    Get_Prefix (Right))
              and then
              Are_Trees_List_Equal (Get_Index_List (Left),
                                    Get_Index_List (Right));
         when Iir_Kind_Slice_Name =>
            return Are_Trees_Equal (Get_Prefix (Left),
                                    Get_Prefix (Right))
              and then Are_Trees_Equal (Get_Suffix (Left),
                                        Get_Suffix (Right));
         when Iir_Kind_Selected_Element =>
            return Are_Trees_Equal (Get_Prefix (Left),
                                    Get_Prefix (Right))
              and then Get_Identifier (Left) = Get_Identifier (Right);

         when Iir_Kind_Parenthesis_Expression =>
            return Are_Trees_Equal (Get_Expression (Left),
                                    Get_Expression (Right));

         when Iir_Kind_Access_Type_Definition
           | Iir_Kind_Record_Type_Definition
           | Iir_Kind_Array_Type_Definition
           | Iir_Kind_Enumeration_Type_Definition
           | Iir_Kind_File_Type_Definition =>
            return Left = Right;

         when Iir_Kind_Range_Expression =>
            if Get_Type (Left) /= Get_Type (Right)
              or else Get_Direction (Left) /= Get_Direction (Right)
            then
               return False;
            end if;
            return Are_Trees_Equal (Get_Left_Limit (Left),
                                    Get_Left_Limit (Right))
              and then Are_Trees_Equal (Get_Right_Limit (Left),
                                        Get_Right_Limit (Right));

         when Iir_Kind_High_Type_Attribute
           | Iir_Kind_Low_Type_Attribute
           | Iir_Kind_Left_Type_Attribute
           | Iir_Kind_Right_Type_Attribute
           | Iir_Kind_Ascending_Type_Attribute =>
            return Are_Trees_Equal (Get_Prefix (Left), Get_Prefix (Right));

         when Iir_Kind_Length_Array_Attribute
            | Iir_Kind_Left_Array_Attribute
            | Iir_Kind_Right_Array_Attribute
            | Iir_Kind_Low_Array_Attribute
            | Iir_Kind_High_Array_Attribute
            | Iir_Kind_Ascending_Array_Attribute =>
            return Are_Trees_Equal (Get_Prefix (Left), Get_Prefix (Right))
              and then
              Are_Trees_Equal (Get_Parameter (Left), Get_Parameter (Right));

         when Iir_Kind_String_Literal8 =>
            if Get_Bit_String_Base (Left) /= Get_Bit_String_Base (Right) then
               return False;
            end if;
            declare
               use Str_Table;
               Len : constant Nat32 := Get_String_Length (Left);
               L_Id : constant String8_Id := Get_String8_Id (Left);
               R_Id : constant String8_Id := Get_String8_Id (Right);
            begin
               if Get_String_Length (Right) /= Len then
                  return False;
               end if;
               for I in 1 .. Len loop
                  if Element_String8 (L_Id, I) /= Element_String8 (R_Id, I)
                  then
                     return False;
                  end if;
               end loop;
               return True;
            end;

         when Iir_Kind_Aggregate =>
            if not Are_Trees_Equal (Get_Type (Left), Get_Type (Right)) then
               return False;
            end if;
            return Are_Trees_Chain_Equal
              (Get_Association_Choices_Chain (Left),
               Get_Association_Choices_Chain (Right));

         when Iir_Kind_Simple_Aggregate =>
            return Are_Trees_Equal (Get_Literal_Origin (Left),
                                    Get_Literal_Origin (Right));

         when Iir_Kind_Choice_By_None
              | Iir_Kind_Choice_By_Others =>
            return Are_Trees_Equal (Get_Associated_Expr (Left),
                                    Get_Associated_Expr (Right));
         when Iir_Kind_Choice_By_Name =>
            if not Are_Trees_Equal (Get_Choice_Name (Left),
                                    Get_Choice_Name (Right))
            then
               return False;
            end if;
            return Are_Trees_Equal (Get_Associated_Expr (Left),
                                    Get_Associated_Expr (Right));
         when Iir_Kind_Choice_By_Expression =>
            if not Are_Trees_Equal (Get_Choice_Expression (Left),
                                    Get_Choice_Expression (Right)) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Associated_Expr (Left),
                                    Get_Associated_Expr (Right));
         when Iir_Kind_Choice_By_Range =>
            if not Are_Trees_Equal (Get_Choice_Range (Left),
                                    Get_Choice_Range (Right)) then
               return False;
            end if;
            return Are_Trees_Equal (Get_Associated_Expr (Left),
                                    Get_Associated_Expr (Right));
         when Iir_Kind_Character_Literal =>
            return Are_Trees_Equal (Get_Named_Entity (Left),
                                    Get_Named_Entity (Right));
         when Iir_Kind_Allocator_By_Subtype =>
            return Are_Trees_Equal (Get_Subtype_Indication (Left),
                                    Get_Subtype_Indication (Right));
         when Iir_Kind_Allocator_By_Expression =>
            return Are_Trees_Equal (Get_Expression (Left),
                                    Get_Expression (Right));
         when others =>
            Error_Kind ("are_trees_equal", Left);
      end case;
   end Are_Trees_Equal;

   --  LRM 2.7  Conformance Rules.
   procedure Check_Conformance_Rules (Subprg, Spec: Iir) is
   begin
      if not Are_Trees_Equal (Subprg, Spec) then
         --  FIXME: should explain why it does not conform ?
         Error_Msg_Sem_Relaxed
           (Subprg, Warnid_Conformance,
            "body of %n does not conform with specification at %l",
            (+Subprg, +Spec));
      end if;
   end Check_Conformance_Rules;

   -- Return the specification corresponding to a declaration DECL, or
   -- null_Iir if none.
   -- FIXME: respect rules of LRM93 2.7
   function Find_Subprogram_Specification (Decl: Iir) return Iir
   is
      Interpretation : Name_Interpretation_Type;
      Decl1: Iir;
      Hash : Iir_Int32;
   begin
      Hash := Get_Subprogram_Hash (Decl);
      Interpretation := Get_Interpretation (Get_Identifier (Decl));
      while Valid_Interpretation (Interpretation) loop
         if not Is_In_Current_Declarative_Region (Interpretation) then
            --  The declaration does not belong to the current declarative
            --  region, neither will the following one.  So, we do not found
            --  it.
            return Null_Iir;
         end if;
         Decl1 := Get_Declaration (Interpretation);
         --  Should be sure DECL1 and DECL belongs to the same declarative
         --  region, ie DECL1 was not made visible via a USE clause.
         --
         --  Also, only check for explicitly subprograms (and not
         --  implicit one).
         if not Is_Implicit_Subprogram (Decl1)
           and then Get_Kind (Decl1) in Iir_Kinds_Subprogram_Declaration
           and then not Is_Potentially_Visible (Interpretation)
           and then Get_Subprogram_Hash (Decl1) = Hash
           and then Is_Same_Profile (Decl, Decl1)
         then
            return Decl1;
         end if;
         Interpretation := Get_Next_Interpretation (Interpretation);
      end loop;
      return Null_Iir;
   end Find_Subprogram_Specification;

   procedure Set_Subprogram_Overload_Number (Decl : Iir)
   is
      Id : constant Name_Id := Get_Identifier (Decl);
      Inter : Name_Interpretation_Type;
      Prev : Iir;
      Num : Iir_Int32;
   begin
      Inter := Get_Interpretation (Id);
      while Valid_Interpretation (Inter)
        and then Is_In_Current_Declarative_Region (Inter)
      loop
         --  There is a previous declaration with the same name in the
         --  current declarative region.
         Prev := Get_Declaration (Inter);
         case Get_Kind (Prev) is
            when Iir_Kind_Function_Declaration
              | Iir_Kind_Procedure_Declaration =>
               if Is_Implicit_Subprogram (Prev) then
                  --  Implicit declarations aren't taken into account (as they
                  --  are mangled differently).
                  Inter := Get_Next_Interpretation (Inter);
               else
                  --  The previous declaration is a user subprogram.
                  Num := Get_Overload_Number (Prev) + 1;
                  if Num = 1
                    and then Get_Parent (Prev) = Get_Parent (Decl)
                  then
                     --  The previous was not (yet) overloaded.  Mark it as
                     --  overloaded.
                     --  Do not mark it if it is not in the same declarative
                     --  part (ie, do not change a subprogram declaration in
                     -- the package while analyzing the body).
                     Set_Overload_Number (Prev, 1);
                     Num := 2;
                  end if;
                  Set_Overload_Number (Decl, Num);
                  return;
               end if;
            when Iir_Kind_Enumeration_Literal =>
               --  Enumeration literal are ignored for overload number.
               Inter := Get_Next_Interpretation (Inter);
            when Iir_Kind_Non_Object_Alias_Declaration =>
               --  Subprogram aliases aren't considered, just skip them.
               --  (No subprogram is created by an alias).
               Inter := Get_Next_Interpretation (Inter);
            when others =>
               --  Case of user error: redefinition of an identifier.
               --  Error message is generated by sem_scope.
               Set_Overload_Number (Decl, 0);
               return;
         end case;
      end loop;
      --  No previous declaration in the current declarative region.
      Set_Overload_Number (Decl, 0);
   end Set_Subprogram_Overload_Number;

   --  Check requirements on number of interfaces for subprogram specification
   --  SUBPRG.  Requirements only concern operators, and are defined in
   --  LRM 2.3.1
   procedure Check_Operator_Requirements (Id : Name_Id; Subprg : Iir)
   is
      use Std_Names;

      Nbr_Interfaces : Natural;
      Is_Method : Boolean;
   begin
      Nbr_Interfaces := Vhdl.Nodes_Utils.Get_Chain_Length
        (Get_Interface_Declaration_Chain (Subprg));

      --  For vhdl-02, the protected variable is an implicit parameter.
      if Flags.Vhdl_Std >= Vhdl_02
        and then Is_Subprogram_Method (Subprg)
      then
         Nbr_Interfaces := Nbr_Interfaces + 1;
      else
         Is_Method := False;
      end if;

      case Id is
         when Name_Abs
           | Name_Not =>
            --  LRM93 2.3.1
            --  The subprogram specification of a unary operator must have a
            --  single parameter.

            --  LRM02 2.3.1
            --  ..., unless the subprogram specification is a method (see
            --  3.5.1) of a protected type.  In this latter case, the
            --  subprogram specification must have no parameters.
            if Nbr_Interfaces = 1 then
               return;
            end if;
            Error_Msg_Sem
              (+Subprg, "unary operator must have a single parameter");
         when Name_Mod
           | Name_Rem
           | Name_Op_Mul
           | Name_Op_Div
           | Name_Relational_Operators
           | Name_Op_Concatenation
           | Name_Shift_Operators
           | Name_Op_Exp =>
            --  LRM93 2.3.1
            --  The subprogram specification of a binary operator must have
            --  two parameters.

            --  LRM02 2.3.1
            --  ..., unless the subprogram specification is a method of a
            --  protected type, in which case, the subprogram specification
            --  must have a single parameter.
            if Nbr_Interfaces = 2 then
               return;
            end if;
            Error_Msg_Sem
              (+Subprg, "binary operators must have two parameters");
         when Name_Logical_Operators
           | Name_Xnor =>
            --  LRM08 4.5.2 Operator overloading
            --  For each of the "+", "-", "and", "or", "xor", "nand", "nor"
            --  and "xnor", overloading is allowed both as a unary operator
            --  and as a binary operator.
            if Nbr_Interfaces = 2 then
               return;
            end if;
            if Nbr_Interfaces = 1 then
               if Vhdl_Std >= Vhdl_08 then
                  return;
               end if;
               Error_Msg_Sem
                 (+Subprg,
                  "logical operators must have two parameters before vhdl08");
            else
               Error_Msg_Sem
                 (+Subprg, "logical operators must have two parameters");
            end if;
         when Name_Op_Plus
           | Name_Op_Minus =>
            --  LRM93 2.3.1
            --  For each of the operators "+" and "-", overloading is allowed
            --  both as a unary operator and as a binary operator.
            if Nbr_Interfaces in 1 .. 2 then
               return;
            end if;
            Error_Msg_Sem
              (+Subprg,
               """+"" and ""-"" operators must have 1 or 2 parameters");
         when others =>
            return;
      end case;
      if Is_Method then
         Error_Msg_Sem
           (+Subprg,
            " (the protected object is an implicit parameter of methods)");
      end if;
   end Check_Operator_Requirements;

   procedure Sem_Subprogram_Specification (Subprg: Iir)
   is
      Interface_Chain : Iir;
      Return_Type : Iir;
   begin
      --  LRM 10.1 Declarative Region
      --  3. A subprogram declaration, together with the corresponding
      --     subprogram body.
      Open_Declarative_Region;

      -- Sem generics.
      if Get_Kind (Subprg) in Iir_Kinds_Subprogram_Declaration then
         Sem_Interface_Chain
           (Get_Generic_Chain (Subprg), Generic_Interface_List);
      end if;

      --  Sem interfaces.
      Interface_Chain := Get_Interface_Declaration_Chain (Subprg);
      case Get_Kind (Subprg) is
         when Iir_Kind_Function_Declaration
           | Iir_Kind_Interface_Function_Declaration =>
            Sem_Interface_Chain
              (Interface_Chain, Function_Parameter_Interface_List);
            Return_Type := Get_Return_Type_Mark (Subprg);
            Return_Type := Sem_Type_Mark (Return_Type);
            Set_Return_Type_Mark (Subprg, Return_Type);
            Return_Type := Get_Type (Return_Type);
            Set_Return_Type (Subprg, Return_Type);
            Set_All_Sensitized_State (Subprg, Unknown);

            --  LRM08 4.2 Subprogram declarations
            --  It is an error if the result subtype of a function denotes
            --  either a file type or a protected type.  Moreover, it is an
            --  error if the result subtype of a pure function denotes an
            --  access type or a subtype that has a subelement of an access
            --  type.

            --  GHDL: this was added by VHDL 2008, but vital packages don't
            --  follow that rule.  So, it is not retroactive.
            case Get_Kind (Return_Type) is
               when Iir_Kind_File_Type_Definition =>
                  Error_Msg_Sem
                    (+Subprg, "result subtype cannot denote a file type");
               when Iir_Kind_Protected_Type_Declaration =>
                  Error_Msg_Sem
                    (+Subprg, "result subtype cannot denote a protected type");
               when Iir_Kind_Access_Type_Definition
                 | Iir_Kind_Access_Subtype_Definition =>
                  if Vhdl_Std >= Vhdl_08
                    and then Get_Pure_Flag (Subprg)
                  then
                     Error_Msg_Sem_Relaxed
                       (Subprg, Warnid_Pure,
                        "result subtype of a pure function cannot denote an"
                          & " access type");
                  end if;
               when Iir_Kind_Error =>
                  null;
               when others =>
                  if  Vhdl_Std >= Vhdl_08
                    and then not Get_Signal_Type_Flag (Return_Type)
                    and then Get_Pure_Flag (Subprg)
                  then
                     Error_Msg_Sem_Relaxed
                       (Subprg, Warnid_Pure,
                        "result subtype of a pure function cannot have"
                          & " access subelements");
                  end if;
            end case;

         when Iir_Kind_Interface_Procedure_Declaration =>
            Sem_Interface_Chain
              (Interface_Chain, Procedure_Parameter_Interface_List);

         when Iir_Kind_Procedure_Declaration =>
            Sem_Interface_Chain
              (Interface_Chain, Procedure_Parameter_Interface_List);

            --  Unless the body is analyzed, the procedure purity is unknown.
            Set_Purity_State (Subprg, Unknown);
            --  Check if the procedure is passive.
            Set_Passive_Flag (Subprg, True);
            Set_All_Sensitized_State (Subprg, Unknown);
            declare
               Inter : Iir;
            begin
               Inter := Interface_Chain;
               while Inter /= Null_Iir loop
                  if Get_Kind (Inter) = Iir_Kind_Interface_Signal_Declaration
                    and then Get_Mode (Inter) /= Iir_In_Mode
                  then
                     --  There is a driver for this signal interface.
                     Set_Passive_Flag (Subprg, False);
                     exit;
                  end if;
                  Inter := Get_Chain (Inter);
               end loop;
            end;

            --  Mark the procedure as suspendable, unless in a std or
            --  most ieee packages.
            --  This is a minor optimization.
            declare
               Lib : constant Iir :=
                 Get_Library (Get_Design_File (Get_Current_Design_Unit));
            begin
               if Lib = Libraries.Std_Library then
                  --  No procedures in std have a wait statement.
                  null;
               elsif Get_Identifier (Lib) = Std_Names.Name_Ieee then
                  --  Package ieee.vital_primitives has wait statements.
                  declare
                     Unit : constant Iir :=
                       Get_Library_Unit (Get_Current_Design_Unit);
                     Unit_Id : constant Name_Id := Get_Identifier (Unit);
                  begin
                     if Unit_Id = Std_Names.Name_VITAL_Primitives then
                        Set_Suspend_Flag (Subprg, True);
                     end if;
                  end;
               else
                  --  User procedures may have wait statements.
                  Set_Suspend_Flag (Subprg, True);
               end if;
            end;
         when others =>
            Error_Kind ("sem_subprogram_declaration", Subprg);
      end case;

      Check_Operator_Requirements (Get_Identifier (Subprg), Subprg);

      Sem_Utils.Compute_Subprogram_Hash (Subprg);

      --  The specification has been analyzed, close the declarative region
      --  now.
      Close_Declarative_Region;
   end Sem_Subprogram_Specification;

   --  LRM 2.1  Subprogram Declarations.
   procedure Sem_Subprogram_Declaration (Subprg: Iir)
   is
      Parent : constant Iir := Get_Parent (Subprg);
      Spec: Iir;
      Subprg_Body : Iir;
   begin
      --  Set depth.
      case Get_Kind (Parent) is
         when Iir_Kind_Function_Declaration
           | Iir_Kind_Procedure_Declaration =>
            raise Internal_Error;
         when Iir_Kind_Function_Body
           | Iir_Kind_Procedure_Body =>
            Set_Subprogram_Depth
              (Subprg,
               Get_Subprogram_Depth
                 (Get_Subprogram_Specification (Parent)) + 1);
         when others =>
            --  FIXME: protected type ?
            Set_Subprogram_Depth (Subprg, 0);
      end case;

      Sem_Subprogram_Specification (Subprg);

      --  Look if there is an associated body (the next node).
      Subprg_Body := Get_Chain (Subprg);
      if Subprg_Body /= Null_Iir
        and then Get_Kind (Subprg_Body) in Iir_Kinds_Subprogram_Body
      then
         Spec := Find_Subprogram_Specification (Subprg);
      else
         Spec := Null_Iir;
      end if;

      if Spec /= Null_Iir then
         -- SUBPRG is the body of the specification SPEC.
         if Get_Subprogram_Body (Spec) /= Null_Iir then
            Error_Msg_Sem (+Subprg, "%n body already defined at %l",
                           (+Spec, +Get_Subprogram_Body (Spec)));
            --  Kill warning.
            Set_Use_Flag (Subprg, True);
         else
            Check_Conformance_Rules (Subprg, Spec);
            Xref_Body (Subprg, Spec);
            Set_Subprogram_Body (Subprg, Subprg_Body);
            Set_Subprogram_Specification (Subprg_Body, Spec);
            Set_Subprogram_Body (Spec, Subprg_Body);
         end if;
      else
         --  Forward declaration or specification followed by body.
         Set_Subprogram_Overload_Number (Subprg);
         Sem_Scopes.Add_Name (Subprg);
         Name_Visible (Subprg);
         Xref_Decl (Subprg);
      end if;
   end Sem_Subprogram_Declaration;

   procedure Add_Analysis_Checks_List (El : Iir)
   is
      Design : constant Iir := Get_Current_Design_Unit;
      List : Iir_List;
   begin
      List := Get_Analysis_Checks_List (Design);
      if List = Null_Iir_List then
         List := Create_Iir_List;
         Set_Analysis_Checks_List (Design, List);
      end if;
      Add_Element (List, El);
   end Add_Analysis_Checks_List;

   procedure Clear_Suspend_Flag (N : Iir);

   procedure Clear_Suspend_Flag_Chain (N : Iir)
   is
      El : Iir;
   begin
      El := N;
      while El /= Null_Iir loop
         Clear_Suspend_Flag (El);
         El := Get_Chain (El);
      end loop;
   end Clear_Suspend_Flag_Chain;

   procedure Clear_Suspend_Flag (N : Iir) is
   begin
      case Iir_Kinds_Sequential_Statement (Get_Kind (N)) is
         when Iir_Kind_Procedure_Call_Statement =>
            Set_Suspend_Flag (N, False);
         when Iir_Kind_For_Loop_Statement
           | Iir_Kind_While_Loop_Statement =>
            Set_Suspend_Flag (N, False);
            Clear_Suspend_Flag_Chain (Get_Sequential_Statement_Chain (N));
         when Iir_Kind_Case_Statement =>
            declare
               Ch : Iir;
               Stmts : Iir;
            begin
               Set_Suspend_Flag (N, False);
               Ch := Get_Case_Statement_Alternative_Chain (N);
               while Ch /= Null_Iir loop
                  Stmts := Get_Associated_Chain (Ch);
                  if Stmts /= Null_Iir then
                     Clear_Suspend_Flag_Chain (Stmts);
                  end if;
                  Ch := Get_Chain (Ch);
               end loop;
            end;
         when Iir_Kind_If_Statement =>
            Set_Suspend_Flag (N, False);
            Clear_Suspend_Flag_Chain (Get_Sequential_Statement_Chain (N));
            declare
               Els : Iir;
            begin
               Els := Get_Else_Clause (N);
               while Els /= Null_Iir loop
                  Clear_Suspend_Flag_Chain
                    (Get_Sequential_Statement_Chain (Els));
                  Els := Get_Else_Clause (Els);
               end loop;
            end;
         when Iir_Kinds_Signal_Assignment_Statement
           | Iir_Kinds_Variable_Assignment_Statement
           | Iir_Kind_Null_Statement
           | Iir_Kind_Assertion_Statement
           | Iir_Kind_Report_Statement
           | Iir_Kinds_Next_Exit_Statement
           | Iir_Kind_Return_Statement
           | Iir_Kind_Break_Statement =>
            null;
         when Iir_Kind_Wait_Statement =>
            raise Internal_Error;
      end case;
   end Clear_Suspend_Flag;

   procedure Sem_Subprogram_Body (Subprg : Iir)
   is
      Spec : constant Iir := Get_Subprogram_Specification (Subprg);
      Warn_Hide_Enabled : constant Boolean := Is_Warning_Enabled (Warnid_Hide);
      Prev_Unelaborated_Use_Allowed : constant Boolean :=
        Unelaborated_Use_Allowed;
      El : Iir;
   begin
      Set_Impure_Depth (Subprg, Iir_Depth_Pure);
      Set_Elaborated_Flag (Spec, True);

      --  LRM 10.1  Declarative regions
      --  3.  A subprogram declaration, together with the corresponding
      --     subprogram body.
      Open_Declarative_Region;
      Set_Is_Within_Flag (Spec, True);

      --  Add the interface names into the current declarative region.
      --  (Do not emit warnings for hiding, they were already emitted during
      --   analysis of the subprogram spec).
      Enable_Warning (Warnid_Hide, False);
      El := Get_Interface_Declaration_Chain (Spec);
      while El /= Null_Iir loop
         Add_Name (El, Get_Identifier (El), False);
         if Get_Kind (El) = Iir_Kind_Interface_Signal_Declaration then
            Set_Has_Active_Flag (El, False);
         end if;
         El := Get_Chain (El);
      end loop;
      Enable_Warning (Warnid_Hide, Warn_Hide_Enabled);

      --  For vhdl-19, handle return identifier.
      if Get_Kind (Spec) = Iir_Kind_Function_Declaration then
         declare
            Ret : constant Iir := Get_Return_Identifier (Spec);
            Ret_Type : Iir;
         begin
            if Ret /= Null_Iir then
               Xrefs.Xref_Decl (Ret);
               Set_Visible_Flag (Ret, True);
               Ret_Type := Get_Type (Spec);
               Ret_Type := Sem_Types.Build_Constrained_Subtype (Ret_Type, Ret);
               Set_Type (Ret, Ret_Type);
               Add_Name (Ret, Get_Identifier (Ret), False);
            end if;
         end;
      end if;

      Unelaborated_Use_Allowed := True;

      Sem_Sequential_Statements (Spec, Subprg);

      Set_Is_Within_Flag (Spec, False);
      Close_Declarative_Region;

      Unelaborated_Use_Allowed := Prev_Unelaborated_Use_Allowed;

      case Get_Kind (Spec) is
         when Iir_Kind_Procedure_Declaration =>
            if Get_Suspend_Flag (Subprg)
              and then not Get_Suspend_Flag (Spec)
            then
               --  Incoherence: procedures declared in std library are not
               --  expected to suspend.  This is an internal check.
               Error_Msg_Sem (+Subprg, "unexpected suspendable procedure");
            end if;

            --  Update purity state of procedure if there are no callees.
            case Get_Purity_State (Spec) is
               when Pure
                 | Maybe_Impure =>
                  --  We can't know this yet.
                  raise Internal_Error;
               when Impure =>
                  null;
               when Unknown =>
                  if Get_Callees_List (Subprg) = Null_Iir_List then
                     --  Since there are no callees, purity state can
                     --  be updated.
                     if Get_Impure_Depth (Subprg) = Iir_Depth_Pure then
                        Set_Purity_State (Spec, Pure);
                     else
                        Set_Purity_State (Spec, Maybe_Impure);
                     end if;
                  end if;
            end case;

            --  Update wait state if the state of all callees is known.
            if Get_Wait_State (Spec) = Unknown then
               declare
                  Callees : constant Iir_List := Get_Callees_List (Subprg);
                  Callees_It : List_Iterator;
                  Callee : Iir;
                  State : Tri_State_Type;
               begin
                  --  Per default, has no wait.
                  Set_Wait_State (Spec, False);
                  Callees_It := List_Iterate_Safe (Callees);
                  while Is_Valid (Callees_It) loop
                     Callee := Get_Element (Callees_It);
                     case Get_Kind (Callee) is
                        when Iir_Kind_Function_Declaration =>
                           null;
                        when Iir_Kind_Procedure_Declaration =>
                           State := Get_Wait_State (Callee);
                           case State is
                              when False =>
                                 null;
                              when Unknown =>
                                 --  Yet unknown, but can be TRUE.
                                 Set_Wait_State (Spec, Unknown);
                              when True =>
                                 --  Can this happen ?
                                 raise Internal_Error;
                                 --Set_Wait_State (Spec, True);
                                 --exit;
                           end case;
                        when others =>
                           Error_Kind ("sem_subprogram_body(2)", Callee);
                     end case;
                     Next (Callees_It);
                  end loop;
               end;
            end if;

            --  There is no wait in this procedure (either directly or
            --  indirectly).  So can clear the suspend flag.
            if Get_Suspend_Flag (Subprg)
              and then Get_Wait_State (Spec) = False
            then
               --  Clear spec only if it has never been used.
               if Get_Chain (Spec) = Subprg then
                  Set_Suspend_Flag (Spec, False);
               end if;
               --  Clear recursively.
               Set_Suspend_Flag (Subprg, False);
               Clear_Suspend_Flag_Chain
                 (Get_Sequential_Statement_Chain (Subprg));
            end if;

            --  Do not add to Analysis_Checks_List as procedures can't
            --  generate purity/wait/all-sensitized errors by themselves.

         when Iir_Kind_Function_Declaration =>
            if Get_Callees_List (Subprg) /= Null_Iir_List then
               --  Purity calls to be checked later.
               --  No wait statements in procedures called.
               Add_Analysis_Checks_List (Spec);
            end if;
         when others =>
            Error_Kind ("sem_subprogram_body", Spec);
      end case;

      --  Set All_Sensitized_State in trivial cases.
      if Get_All_Sensitized_State (Spec) = Unknown
        and then Get_Callees_List (Subprg) = Null_Iir_List
      then
         Set_All_Sensitized_State (Spec, No_Signal);
      end if;
   end Sem_Subprogram_Body;

   function Sem_Uninstantiated_Subprogram_Name (Decl : Iir) return Iir
   is
      Name : Iir;
      Subprg : Iir;
   begin
      Name := Get_Uninstantiated_Subprogram_Name (Decl);
      if Get_Kind (Name) = Iir_Kind_Signature then
         --  TODO
         raise Internal_Error;
      end if;

      Name := Sem_Denoting_Name (Name);
      Set_Uninstantiated_Subprogram_Name (Decl, Name);
      Subprg := Get_Named_Entity (Name);
      if Is_Error (Subprg) then
         return Subprg;
      end if;

      if Is_Overload_List (Subprg) then
         --  TODO
         raise Internal_Error;
      end if;

      if Get_Kind (Subprg) not in Iir_Kinds_Subprogram_Declaration then
         Error_Class_Match (Name, "package");
         return Create_Error (Subprg);
      end if;

      case Get_Kind (Decl) is
         when Iir_Kind_Procedure_Instantiation_Declaration =>
            if Get_Kind (Subprg) /= Iir_Kind_Procedure_Declaration then
               Error_Msg_Sem
                 (+Name,
                  "a procedure instantiation cannot instantiate %i", +Subprg);
               return Create_Error (Subprg);
            end if;
         when Iir_Kind_Function_Instantiation_Declaration =>
            if Get_Kind (Subprg) /= Iir_Kind_Function_Declaration then
               Error_Msg_Sem
                 (+Name,
                  "a function instantiation cannot instantiate %i", +Subprg);
               return Create_Error (Subprg);
            end if;
         when others =>
            raise Internal_Error;
      end case;

      if not Is_Uninstantiated_Subprogram (Subprg) then
         Error_Msg_Sem
           (+Name, "%n is not an uninstantiated subprogram", +Subprg);
         return Create_Error (Subprg);
      end if;

      return Subprg;
   end Sem_Uninstantiated_Subprogram_Name;

   procedure Sem_Subprogram_Instantiation_Declaration (Decl : Iir)
   is
      Subprg : Iir;
   begin
      Xref_Decl (Decl);

      Subprg := Sem_Uninstantiated_Subprogram_Name (Decl);
      if Subprg = Null_Iir or Is_Error (Subprg) then
         --  What could be done ?
         return;
      end if;

      --  LRM08 4.4 Subprogram instantiation declarations
      --  The generic map aspect, if present, optionally associates a single
      --  actual with each formal generic (or member thereof) in the
      --  corresponding subprogram declaration.  Each formal generic (of member
      --  thereof) shall be associated at most once.
      if not Sem_Generic_Association_Chain (Subprg, Decl) then
         --  FIXME: stop analysis here ?
         return;
      end if;

      --  Create the interface parameters.
      Sem_Inst.Instantiate_Subprogram_Declaration (Decl, Subprg);

      --  Add DECL.  Must be done after parameters creation to handle
      --  homographs.
      Sem_Scopes.Add_Name (Decl);
      Set_Visible_Flag (Decl, True);
   end Sem_Subprogram_Instantiation_Declaration;

   --  Return the subprogram body of SPEC.  If there is no body, and if SPEC
   --  is an instance, returns the body of the generic specification but only
   --  if known.
   function Get_Subprogram_Body_Or_Generic (Spec : Iir) return Iir
   is
      Bod : Iir;
      Orig : Iir;
   begin
      Bod := Get_Subprogram_Body (Spec);

      if Bod /= Null_Iir then
         return Bod;
      end if;

      Orig := Sem_Inst.Get_Origin (Spec);
      if Orig = Null_Iir then
         return Null_Iir;
      end if;

      return Get_Subprogram_Body (Orig);
   end Get_Subprogram_Body_Or_Generic;

   --  Status of Update_And_Check_Pure_Wait.
   type Update_Pure_Status is
     (
      --  The purity/wait/all-sensitized are computed and known.
      Update_Pure_Done,
      --  A missing body prevents from computing the purity/wait/all-sensitized
      Update_Pure_Missing,
      --  Purity/wait/all-sensitized is unknown (recursion).
      Update_Pure_Unknown
     );

   function Update_And_Check_Pure_Wait (Subprg : Iir) return Update_Pure_Status
   is
      procedure Error_Wait (Caller : Iir; Callee : Iir) is
      begin
         Report_Start_Group;
         Error_Msg_Sem
           (+Caller, "%n must not contain wait statement, but calls", +Caller);
         Error_Msg_Sem
           (+Callee, "%n which has (indirectly) a wait statement", +Callee);
         Report_End_Group;
      end Error_Wait;

      --  Kind of subprg.
      type Caller_Kind is (K_Function, K_Process, K_Procedure);
      Kind : Caller_Kind;

      Callees_List : Iir_List;
      Callees_List_Holder : Iir;
      Callees_It : List_Iterator;
      Callee : Iir;
      Callee_Bod : Iir;
      Subprg_Depth : Iir_Int32;
      Subprg_Bod : Iir;
      --  Current purity depth of SUBPRG.
      Depth : Iir_Int32;
      Depth_Callee : Iir_Int32;
      Has_Wait_Errors : Boolean := False;
      New_List : Iir_List;
      Res, Res1 : Update_Pure_Status;
   begin
      case Get_Kind (Subprg) is
         when Iir_Kind_Function_Declaration =>
            Kind := K_Function;
            Subprg_Bod := Get_Subprogram_Body_Or_Generic (Subprg);
            if Subprg_Bod = Null_Iir then
               return Update_Pure_Missing;
            end if;
            Subprg_Depth := Get_Subprogram_Depth (Subprg);
            Callees_List_Holder := Subprg_Bod;
            if Get_Pure_Flag (Subprg) then
               Depth := Iir_Depth_Pure;
            else
               Depth := Iir_Depth_Impure;
            end if;

         when Iir_Kind_Procedure_Declaration =>
            Kind := K_Procedure;
            Subprg_Bod := Get_Subprogram_Body_Or_Generic (Subprg);
            if Subprg_Bod = Null_Iir then
               return Update_Pure_Missing;
            end if;
            if Get_Purity_State (Subprg) = Impure
              and then Get_Wait_State (Subprg) /= Unknown
              and then Get_All_Sensitized_State (Subprg) /= Unknown
            then
               --  No need to go further.
               if Get_All_Sensitized_State (Subprg) = No_Signal
                 or else Vhdl_Std < Vhdl_08
               then
                  Callees_List := Get_Callees_List (Subprg_Bod);
                  Destroy_Iir_List (Callees_List);
                  Set_Callees_List (Subprg_Bod, Null_Iir_List);
               end if;
               return Update_Pure_Done;
            end if;
            Subprg_Depth := Get_Subprogram_Depth (Subprg);
            Depth := Get_Impure_Depth (Subprg_Bod);
            Callees_List_Holder := Subprg_Bod;

         when Iir_Kind_Sensitized_Process_Statement =>
            Kind := K_Process;
            Subprg_Bod := Null_Iir;
            Subprg_Depth := Iir_Depth_Top;
            Depth := Iir_Depth_Impure;
            Callees_List_Holder := Subprg;

         when others =>
            Error_Kind ("update_and_check_pure_wait(1)", Subprg);
      end case;

      --  If the subprogram has no callee list, there is nothing to do.
      Callees_List := Get_Callees_List (Callees_List_Holder);
      if Callees_List = Null_Iir_List then
         --  There are two reasons why a callees_list is null:
         --  * either because SUBPRG does not call any procedure
         --    in this case, the status are already known and we should have
         --    returned in the above case.
         --  * or because of a recursion
         --    in this case the status are still unknown here.
         return Update_Pure_Unknown;
      end if;

      --  By default we don't know the status.
      Res := Update_Pure_Unknown;

      --  This subprogram is being considered.
      --  To avoid infinite loop, suppress its callees list.
      Set_Callees_List (Callees_List_Holder, Null_Iir_List);

      --  First loop: check without recursion.
      --  Second loop: recurse if necessary.
      for J in 0 .. 1 loop
         New_List := Create_Iir_List;
         Callees_It := List_Iterate (Callees_List);
         while Is_Valid (Callees_It) loop
            Callee := Get_Element (Callees_It);

            --  Note:
            --  Pure functions should not be in the list.
            --  Impure functions must have directly set Purity_State.

            --  The body of subprograms may not be set for instances.
            --  Use the body from the generic (if any).
            --  This is meaningful for non macro-expanded package interface,
            --  because there is no associated body and because the call
            --  tree is known (if there were an interface subprogram, it
            --  would have been macro-expanded).
            --  Do not set the body, as it would trigger an assert during
            --  macro-expansion (maybe this shouldn't be called for macro
            --  expanded packages).
            Callee_Bod := Get_Subprogram_Body_Or_Generic (Callee);

            --  Check pure.
            if Callee_Bod = Null_Iir then
               --  No body yet for the subprogram called.
               --  Nothing can be extracted from it, postpone the checks until
               --  elaboration.
               Res := Update_Pure_Missing;
            else
               --  Second loop: recurse if a state is not known.
               if J = 1
                 and then
                 ((Get_Kind (Callee) = Iir_Kind_Procedure_Declaration
                     and then Get_Purity_State (Callee) = Unknown)
                  or else Get_Wait_State (Callee) = Unknown
                  or else Get_All_Sensitized_State (Callee) = Unknown)
               then
                  Res1 := Update_And_Check_Pure_Wait (Callee);
                  if Res1 = Update_Pure_Missing then
                     Res := Update_Pure_Missing;
                  end if;
               end if;

               --  Check purity only if the subprogram is not impure.
               if Depth /= Iir_Depth_Impure then
                  Depth_Callee := Get_Impure_Depth (Callee_Bod);

                  --  Check purity depth.
                  if Depth_Callee < Subprg_Depth then
                     --  The call is an impure call because it calls an outer
                     --   subprogram (or an impure subprogram).
                     --  FIXME: check the compare.
                     Depth_Callee := Iir_Depth_Impure;
                     if Kind = K_Function then
                        --  FIXME: report call location
                        Error_Pure (Elaboration, Subprg_Bod, Callee, Null_Iir);
                     end if;
                  end if;

                  --  Update purity depth.
                  if Depth_Callee < Depth then
                     Depth := Depth_Callee;
                     if Kind = K_Procedure then
                        --  Update for recursivity.
                        Set_Impure_Depth (Subprg_Bod, Depth);
                        if Depth = Iir_Depth_Impure then
                           Set_Purity_State (Subprg, Impure);
                        end if;
                     end if;
                  end if;
               end if;
            end if;

            --  Check wait.
            if Has_Wait_Errors = False
              and then Get_Wait_State (Callee) = True
            then
               if Kind = K_Procedure then
                  Set_Wait_State (Subprg, True);
               else
                  Error_Wait (Subprg, Callee);
                  Has_Wait_Errors := True;
               end if;
            end if;

            if Get_All_Sensitized_State (Callee) = Invalid_Signal then
               case Kind is
                  when K_Function | K_Procedure =>
                     Set_All_Sensitized_State (Subprg, Invalid_Signal);
                  when K_Process =>
                     --  LRM08 11.3
                     --
                     --  It is an error if a process statement with the
                     --  reserved word ALL as its process sensitivity list
                     --  is the parent of a subprogram declared in a design
                     --  unit other than that containing the process statement
                     --  and the subprogram reads an explicitly declared
                     --  signal that is not a formal signal parameter or
                     --  member of a formal signal parameter of the
                     --  subprogram or of any of its parents.  Similarly,
                     --  it is an error if such subprogram reads an implicit
                     --  signal whose explicit ancestor is not a formal signal
                     --  parameter or member of a formal parameter of
                     --  the subprogram or of any of its parents.
                     Report_Start_Group;
                     Error_Msg_Sem
                       (+Subprg, "all-sensitized %n can't call %n",
                        (+Subprg, +Callee));
                     Error_Msg_Sem
                       (+Subprg,
                        " (as this subprogram reads (indirectly) a signal)");
                     Report_End_Group;
               end case;
            end if;

            --  Keep in list.
            if Callee_Bod = Null_Iir
              or else
              (Get_Kind (Callee) = Iir_Kind_Procedure_Declaration
                 and then Get_Purity_State (Callee) = Unknown
                 and then Depth /= Iir_Depth_Impure)
              or else
              (Get_Wait_State (Callee) = Unknown
                 and then (Kind /= K_Procedure
                             or else Get_Wait_State (Subprg) = Unknown))
              or else
              (Vhdl_Std >= Vhdl_08
                 and then
                 (Get_All_Sensitized_State (Callee) = Unknown
                    or else Get_All_Sensitized_State (Callee) = Read_Signal))
            then
               Append_Element (New_List, Callee);
            end if;
            Next (Callees_It);
         end loop;

         --  End of callee loop.
         if Is_Empty (New_List) then
            Destroy_Iir_List (Callees_List);
            Callees_List := Null_Iir_List;
            Destroy_Iir_List (New_List);
            if Kind = K_Procedure then
               if Get_Purity_State (Subprg) = Unknown then
                  Set_Purity_State (Subprg, Maybe_Impure);
               end if;
               if Get_Wait_State (Subprg) = Unknown then
                  Set_Wait_State (Subprg, False);
               end if;
            end if;
            if Kind = K_Procedure or Kind = K_Function then
               if Get_All_Sensitized_State (Subprg) = Unknown then
                  Set_All_Sensitized_State (Subprg, No_Signal);
               end if;
            end if;
            Res := Update_Pure_Done;
            exit;
         else
            Destroy_Iir_List (Callees_List);
            Callees_List := New_List;
         end if;
      end loop;

      Set_Callees_List (Callees_List_Holder, New_List);

      return Res;
   end Update_And_Check_Pure_Wait;

   --  Check pure/wait/all-sensitized issues for SUBPRG (subprogram or
   --  process).  Return False if the analysis is incomplete (and must
   --  be deferred).
   function Root_Update_And_Check_Pure_Wait (Subprg : Iir) return Boolean
   is
      Res : Update_Pure_Status;
   begin
      Res := Update_And_Check_Pure_Wait (Subprg);
      case Res is
         when Update_Pure_Done =>
            return True;
         when Update_Pure_Missing =>
            return False;
         when Update_Pure_Unknown =>
            --  The purity/wait is unknown, but all callee were walked.
            --  This means there are recursive calls but without violations.
            if Get_Kind (Subprg) = Iir_Kind_Procedure_Declaration then
               if Get_Purity_State (Subprg) = Unknown then
                  Set_Purity_State (Subprg, Maybe_Impure);
               end if;
               if Get_Wait_State (Subprg) = Unknown then
                  Set_Wait_State (Subprg, False);
               end if;
            end if;
            if Get_Kind (Subprg) in Iir_Kinds_Subprogram_Declaration then
               if Get_All_Sensitized_State (Subprg) = Unknown then
                  Set_All_Sensitized_State (Subprg, No_Signal);
               end if;
            end if;
            return True;
      end case;
   end Root_Update_And_Check_Pure_Wait;

   procedure Sem_Analysis_Checks_List (Unit : Iir_Design_Unit;
                                       Emit_Warnings : Boolean)
   is
      List : Iir_List;
      El : Iir;
      It : List_Iterator;
      Keep : Boolean;
      New_List : Iir_List;
   begin
      List := Get_Analysis_Checks_List (Unit);
      if List = Null_Iir_List then
         --  Return now if there is nothing to check.
         return;
      end if;

      New_List := Create_Iir_List;
      It := List_Iterate (List);
      while Is_Valid (It) loop
         El := Get_Element (It);
         Keep := False;
         case Get_Kind (El) is
            when Iir_Kind_Function_Declaration =>
               --  FIXME: remove from list if fully tested ?
               if not Root_Update_And_Check_Pure_Wait (El) then
                  Keep := True;
                  if Emit_Warnings then
                     declare
                        Bod : constant Iir := Get_Subprogram_Body (El);
                        Callees : constant Iir_List := Get_Callees_List (Bod);
                        pragma Assert (Callees /= Null_Iir_List);
                        Callee : constant Iir := Get_First_Element (Callees);
                     begin
                        Report_Start_Group;
                        Warning_Msg_Sem
                          (Warnid_Delayed_Checks, +El,
                           "can't assert that all calls in %n"
                             & " are pure or have not wait;"
                             & " will be checked at elaboration", +El);
                        --  FIXME: could improve this message by displaying
                        --  the chain of calls until the first subprograms in
                        --  unknown state.
                        Warning_Msg_Sem
                          (Warnid_Delayed_Checks, +Callee,
                           "(first such call is to %n)", +Callee);
                        Report_End_Group;
                     end;
                  end if;
               end if;
            when Iir_Kind_Sensitized_Process_Statement =>
               if not Root_Update_And_Check_Pure_Wait (El) then
                  Keep := True;
                  if Emit_Warnings then
                     Warning_Msg_Sem
                       (Warnid_Delayed_Checks, +El,
                        "can't assert that %n has no wait; "
                          & "will be checked at elaboration", +El);
                  end if;
               end if;
            when others =>
               Error_Kind ("sem_analysis_checks_list", El);
         end case;
         if Keep then
            Append_Element (New_List, El);
         end if;
         Next (It);
      end loop;
      if Is_Empty (New_List) then
         Destroy_Iir_List (New_List);
         New_List := Null_Iir_List;  --  OK, redundant but clearer.
      end if;
      Destroy_Iir_List (List);
      Set_Analysis_Checks_List (Unit, New_List);
   end Sem_Analysis_Checks_List;

   --  Return true if package declaration DECL needs a body.
   --  Ie, it contains subprogram specification or deferred constants.
   function Package_Need_Body_P (Decl: Iir_Package_Declaration)
                                return Boolean
   is
      El: Iir;
      Def : Iir;
   begin
      El := Get_Declaration_Chain (Decl);
      while El /= Null_Iir loop
         case Get_Kind (El) is
            when Iir_Kind_Function_Declaration
              | Iir_Kind_Procedure_Declaration =>
               if not Is_Implicit_Subprogram (El) then
                  return True;
               end if;
            when Iir_Kind_Constant_Declaration =>
               if Get_Default_Value (El) = Null_Iir then
                  return True;
               end if;
            when Iir_Kind_Variable_Declaration
              | Iir_Kind_File_Declaration
              | Iir_Kind_Signal_Declaration
              | Iir_Kind_Object_Alias_Declaration
              | Iir_Kind_Non_Object_Alias_Declaration
              | Iir_Kind_Group_Template_Declaration
              | Iir_Kind_Group_Declaration =>
               null;
            when Iir_Kind_Type_Declaration =>
               Def := Get_Type_Definition (El);
               if Def /= Null_Iir
                 and then Get_Kind (Def) = Iir_Kind_Protected_Type_Declaration
               then
                  return True;
               end if;
            when Iir_Kind_Anonymous_Type_Declaration
              | Iir_Kind_Subtype_Declaration =>
               null;
            when Iir_Kind_Attribute_Declaration
              | Iir_Kind_Attribute_Specification =>
               null;
            when Iir_Kind_Disconnection_Specification =>
               null;
            when Iir_Kind_Use_Clause =>
               null;
            when Iir_Kind_Component_Declaration =>
               null;
            when Iir_Kind_Protected_Type_Body =>
               null;
            when Iir_Kind_Package_Declaration =>
               --  LRM08 4.8 Package bodies
               --  A package body that is not a library unit shall appear
               --  immediately within the same declarative region as the
               --  corresponding package declaration and textually subsequent
               --  to that package declaration.
               if Get_Need_Body (El) then
                  return True;
               end if;
            when Iir_Kind_Package_Body =>
               null;
            when Iir_Kind_Package_Instantiation_Declaration =>
               null;
            when Iir_Kind_Nature_Declaration
              | Iir_Kind_Subnature_Declaration =>
               null;
            when Iir_Kind_Terminal_Declaration =>
               null;
            when Iir_Kind_Mode_View_Declaration =>
               null;
            when others =>
               pragma Assert (Flags.Flag_Force_Analysis);
               null;
         end case;
         El := Get_Chain (El);
      end loop;
      return False;
   end Package_Need_Body_P;

   --  Return true if package declaration DECL contains at least one package
   --  instantiation that needs a body.
   function Package_Need_Instance_Bodies_P (Decl: Iir_Package_Declaration)
                                           return Boolean
   is
      El: Iir;
   begin
      El := Get_Declaration_Chain (Decl);
      while El /= Null_Iir loop
         case Get_Kind (El) is
            when Iir_Kind_Package_Instantiation_Declaration =>
               declare
                  Pkg : constant Iir := Get_Uninstantiated_Package_Decl (El);
               begin
                  if not Is_Error (Pkg)
                    and then Get_Need_Body (Pkg)
                  then
                     return True;
                  end if;
               end;
            when others =>
               null;
         end case;
         El := Get_Chain (El);
      end loop;
      return False;
   end Package_Need_Instance_Bodies_P;

   --  Return true if uninstantiated pckage DECL must be macro-expanded (at
   --  least one interface type).
   function Is_Package_Macro_Expanded
     (Decl : Iir_Package_Declaration) return Boolean
   is
      Header : constant Iir := Get_Package_Header (Decl);
      Inter : Iir;
   begin
      Inter := Get_Generic_Chain (Header);
      while Is_Valid (Inter) loop
         case Iir_Kinds_Interface_Declaration (Get_Kind (Inter)) is
            when Iir_Kinds_Interface_Object_Declaration
              | Iir_Kind_Interface_Terminal_Declaration =>
               null;
            when Iir_Kind_Interface_Type_Declaration =>
               return True;
            when Iir_Kind_Interface_Package_Declaration =>
               declare
                  Pkg : constant Iir :=
                    Get_Uninstantiated_Package_Decl (Inter);
               begin
                  --  Could be an error.
                  if Get_Kind (Pkg) = Iir_Kind_Package_Declaration
                    and then Get_Macro_Expand_Flag (Pkg)
                  then
                     return True;
                  end if;
               end;
            when Iir_Kinds_Interface_Subprogram_Declaration =>
               return True;
         end case;
         Inter := Get_Chain (Inter);
      end loop;
      return False;
   end Is_Package_Macro_Expanded;

   --  LRM 2.5  Package Declarations.
   procedure Sem_Package_Declaration (Pkg : Iir_Package_Declaration)
   is
      Unit : constant Iir_Design_Unit := Get_Design_Unit (Pkg);
      Header : constant Iir := Get_Package_Header (Pkg);
      Implicit : Implicit_Declaration_Type;
   begin
      Sem_Scopes.Add_Name (Pkg);
      Set_Visible_Flag (Pkg, True);
      Xref_Decl (Pkg);

      Set_Is_Within_Flag (Pkg, True);

      --  Identify IEEE.Std_Logic_1164 for VHDL08.
      if Get_Identifier (Pkg) = Std_Names.Name_Std_Logic_1164
        and then (Get_Identifier (Get_Library (Get_Design_File (Unit)))
                    = Std_Names.Name_Ieee)
      then
         Vhdl.Ieee.Std_Logic_1164.Std_Logic_1164_Pkg := Pkg;
      end if;

      --  LRM93 10.1 Declarative Region
      --  4. A package declaration, together with the corresponding
      --     body (if any).
      Open_Declarative_Region;

      Push_Signals_Declarative_Part (Implicit, Pkg);

      if Header /= Null_Iir then
         declare
            Generic_Chain : constant Iir := Get_Generic_Chain (Header);
            Generic_Map : constant Iir :=
              Get_Generic_Map_Aspect_Chain (Header);
            Assoc_El : Iir;
            Inter_El : Iir;
            Inter : Iir;
         begin
            Sem_Interface_Chain (Generic_Chain, Generic_Interface_List);

            if Generic_Map /= Null_Iir then
               --  Generic-mapped packages are not macro-expanded.
               Set_Macro_Expand_Flag (Pkg, False);

               if Sem_Generic_Association_Chain (Header, Header) then
                  --  For generic-mapped packages, use the actual type for
                  --  interface type.
                  Assoc_El := Get_Generic_Map_Aspect_Chain (Header);
                  Inter_El := Generic_Chain;
                  while Is_Valid (Assoc_El) loop
                     if Get_Kind (Assoc_El) = Iir_Kind_Association_Element_Type
                     then
                        Inter :=
                          Get_Association_Interface (Assoc_El, Inter_El);
                        Sem_Inst.Substitute_On_Chain
                          (Generic_Chain,
                           Get_Type (Inter),
                           Get_Type (Get_Named_Entity
                                       (Get_Actual (Assoc_El))));
                     end if;
                     Next_Association_Interface (Assoc_El, Inter_El);
                  end loop;
               end if;
            else
               --  Uninstantiated package.  Maybe macro expanded.
               Set_Macro_Expand_Flag
                 (Pkg, Is_Package_Macro_Expanded (Pkg));
            end if;
         end;
      else
         --  Simple packages are never expanded.
         Set_Macro_Expand_Flag (Pkg, False);
      end if;

      Sem_Declaration_Chain (Pkg);
      Mark_Declarations_Elaborated (Pkg, True);
      --  GHDL: subprogram bodies appear in package body.

      Pop_Signals_Declarative_Part (Implicit);
      Close_Declarative_Region;
      Set_Is_Within_Flag (Pkg, False);

      Set_Need_Body (Pkg, Package_Need_Body_P (Pkg));

      if Vhdl_Std >= Vhdl_08 then
         Set_Need_Instance_Bodies
           (Pkg, Package_Need_Instance_Bodies_P (Pkg));
      end if;
   end Sem_Package_Declaration;

   --  LRM 2.6  Package Bodies.
   procedure Sem_Package_Body (Decl : Iir)
   is
      Package_Ident : constant Name_Id := Get_Identifier (Decl);
      Is_Top_Level : constant Boolean := not Is_Nested_Package (Decl);
      Package_Decl : Iir;
      Implicit : Implicit_Declaration_Type;
   begin
      -- First, find the package declaration.
      if Is_Top_Level then
         declare
            Design_Unit: Iir_Design_Unit;
         begin
            Design_Unit := Load_Primary_Unit
              (Get_Library (Get_Design_File (Get_Current_Design_Unit)),
               Package_Ident, Decl);
            if Design_Unit = Null_Iir then
               Error_Msg_Sem
                 (+Decl, "package %i was not analysed", +Package_Ident);
               return;
            end if;

            Package_Decl := Get_Library_Unit (Design_Unit);
            if Get_Kind (Package_Decl) /= Iir_Kind_Package_Declaration then
               Error_Msg_Sem
                 (+Decl, "primary unit %i is not a package", +Package_Ident);
               return;
            end if;

            --  LRM08 13.5 Order of analysis
            --  In each case, the second unit depends on the first unit
            Add_Dependence (Design_Unit);

            Add_Name (Design_Unit);

            --  Add the context clauses from the primary unit.
            Add_Context_Clauses (Design_Unit);
         end;
      else
         declare
            Interp : Name_Interpretation_Type;
         begin
            Interp := Get_Interpretation (Get_Identifier (Decl));
            if not Valid_Interpretation (Interp)
              or else not Is_In_Current_Declarative_Region (Interp)
              or else Is_Potentially_Visible (Interp)
            then
               Error_Msg_Sem
                 (+Decl, "no corresponding package declaration for %i",
                  +Package_Ident);
               return;
            end if;

            Package_Decl := Get_Declaration (Interp);
            if Get_Kind (Package_Decl) /= Iir_Kind_Package_Declaration then
               Error_Msg_Sem
                 (+Decl, "declaration %i is not a package", +Package_Ident);
               return;
            end if;
         end;
      end if;

      --  Emit a warning is a body is not necessary.
      if not Get_Need_Body (Package_Decl) then
         Warning_Msg_Sem (Warnid_Body, +Decl,
                          "%n does not require a body", +Package_Decl);
      end if;

      Set_Package (Decl, Package_Decl);
      Xref_Body (Decl, Package_Decl);
      Set_Package_Body (Package_Decl, Decl);
      Set_Is_Within_Flag (Package_Decl, True);

      --  Unmark subprograms from the specifications: they are not elaborated
      --  before body elaboration.
      Mark_Declarations_Elaborated (Package_Decl, False);

      --  LRM93 10.1 Declarative Region
      --  4. A package declaration, together with the corresponding
      --     body (if any).
      Open_Declarative_Region;

      if Is_Top_Level then
         Push_Signals_Declarative_Part (Implicit, Decl);
      end if;

      Sem_Scopes.Add_Package_Declarations (Package_Decl);

      Sem_Declaration_Chain (Decl);

      --  Check presence of bodies for declarations in the package body.
      Check_Full_Declaration (Decl, Decl);

      --  Check presence of bodies for declarations in the package declaration.
      Check_Full_Declaration (Package_Decl, Decl);

      if Is_Top_Level then
         Pop_Signals_Declarative_Part (Implicit);
      end if;

      Close_Declarative_Region;
      Set_Is_Within_Flag (Package_Decl, False);
   end Sem_Package_Body;

   function Sem_Uninstantiated_Package_Name (Decl : Iir) return Iir
   is
      Name : Iir;
      Pkg : Iir;
   begin
      Name := Get_Uninstantiated_Package_Name (Decl);
      if Get_Kind (Name) not in Iir_Kinds_Denoting_Name then
         Error_Msg_Sem (+Name, "uninstantiated package name expected");
         Pkg := Create_Error (Name);
      else
         Name := Sem_Denoting_Name (Name);
         Set_Uninstantiated_Package_Name (Decl, Name);
         Pkg := Get_Named_Entity (Name);
         if Is_Error (Pkg) then
            null;
         elsif Get_Kind (Pkg) /= Iir_Kind_Package_Declaration then
            Error_Class_Match (Name, "package");
            Pkg := Create_Error (Pkg);
         elsif not Is_Uninstantiated_Package (Pkg) then
            Error_Msg_Sem (+Name, "%n is not an uninstantiated package", +Pkg);
            Pkg := Create_Error (Pkg);
         end if;
      end if;

      Set_Uninstantiated_Package_Decl (Decl, Pkg);

      return Pkg;
   end Sem_Uninstantiated_Package_Name;

   --  LRM08 4.9  Package Instantiation Declaration
   procedure Sem_Package_Instantiation_Declaration (Decl : Iir)
   is
      Hdr : Iir;
      Pkg : Iir;
      Bod : Iir_Design_Unit;
      Parent : Iir;
   begin
      Sem_Scopes.Add_Name (Decl);
      Set_Visible_Flag (Decl, True);
      Xref_Decl (Decl);

      --  LRM08 4.9
      --  The uninstantiated package name shall denote an uninstantiated
      --  package declared in a package declaration.
      Pkg := Sem_Uninstantiated_Package_Name (Decl);
      if Pkg = Null_Iir or Is_Error (Pkg) then
         --  What could be done ?
         return;
      end if;

      --  LRM08 4.9
      --  The generic map aspect, if present, optionally associates a single
      --  actual with each formal generic (or member thereof) in the
      --  corresponding package declaration.  Each formal generic (or member
      --  thereof) shall be associated at most once.

      --  GHDL: the generics are first instantiated (ie copied) and then
      --  the actuals are associated with the instantiated formal.
      --  FIXME: do it in Instantiate_Package_Declaration ?
      Hdr := Get_Package_Header (Pkg);
      if not Sem_Generic_Association_Chain (Hdr, Decl) then
         --  FIXME: stop analysis here ?
         return;
      end if;

      --  Add dependency to the package body
      --  FIXME: unless the parent is a package declaration library unit, the
      --  design unit depends on the body.
      if not Is_Nested_Package (Pkg) then
         --  Find the body
         Bod := Libraries.Find_Secondary_Unit
           (Get_Design_Unit (Pkg), Null_Identifier);
         if Is_Null (Bod) then
            --  It's an error if the body is required
            if Get_Need_Body (Pkg) then
               Error_Msg_Sem (+Decl, "cannot find package body of %n", +Pkg);
            end if;
         else
            --  As there is a body, the unit depends on it.
            --  Force the need body flag, so that the body will be expanded
            --  if needed
            Set_Need_Body (Pkg, True);
            --  TODO: load only if the package is macro expanded
            Bod := Load_Secondary_Unit
              (Get_Design_Unit (Pkg), Null_Identifier, Decl);
            if Bod /= Null_Iir then
               Add_Dependence (Bod);
            end if;
         end if;
      else
         Bod := Null_Iir;
      end if;

      --  Instantiate the declaration after analyse of the body.  So that
      --  the use_flag on the declaration can be propagated to the instance.
      Sem_Inst.Instantiate_Package_Declaration (Decl, Pkg);

      --  LRM08 4.9 Package instantiation declarations
      --  If the package instantiation declaration occurs immediately within
      --  an encloding package declaration [...], the generic-mapped package
      --  body occurs at the end of the package body corresponding to the
      --  enclosing package declaration.
      Parent := Get_Parent (Decl);
      if Get_Kind (Parent) = Iir_Kind_Package_Declaration then
         Set_Immediate_Body_Flag (Decl, False);
         Mark_Declarations_Elaborated (Decl, False);
      else
         if Get_Need_Body (Pkg) or else Bod /= Null_Iir then
            Set_Immediate_Body_Flag (Decl, True);
         end if;
      end if;
   end Sem_Package_Instantiation_Declaration;

   --  LRM 10.4  Use Clauses.
   procedure Sem_Use_Clause_Name (Clause : Iir)
   is
      Name: Iir;
      Prefix: Iir;
      Name_Prefix : Iir;
   begin
      --  LRM93 10.4
      --  A use clause achieves direct visibility of declarations that are
      --  visible by selection.
      --  Each selected name is a use clause identifies one or more
      --  declarations that will potentialy become directly visible.

      Name := Get_Selected_Name (Clause);
      if Name = Null_Iir then
         pragma Assert (Flags.Flag_Force_Analysis);
         return;
      end if;

      case Get_Kind (Name) is
         when Iir_Kind_Selected_By_All_Name
           | Iir_Kind_Selected_Name =>
            Name_Prefix := Get_Prefix (Name);
         when others =>
            Error_Msg_Sem (+Name, "use clause allows only selected name");
            Set_Selected_Name (Clause, Create_Error_Name (Name));
            return;
      end case;

      case Get_Kind (Name_Prefix) is
         when Iir_Kind_Simple_Name
           | Iir_Kind_Selected_Name =>
            null;
         when others =>
            Error_Msg_Sem
              (+Name_Prefix,
               "use clause prefix must be a name or a selected name");
            Set_Selected_Name (Clause, Create_Error_Name (Name));
            return;
      end case;

      Name_Prefix := Sem_Denoting_Name (Name_Prefix);
      Set_Prefix (Name, Name_Prefix);
      Prefix := Get_Named_Entity (Name_Prefix);
      if Is_Error (Prefix) then
         Set_Selected_Name (Clause, Create_Error_Name (Name));
         return;
      end if;

      --  LRM 10.4 Use Clauses
      --
      --  If the suffix of the selected name is [...], then the
      --  selected name identifies only the declaration(s) of that
      --  [...] contained within the package or library denoted by
      --  the prefix of the selected name.
      --
      --  If the suffix is the reserved word ALL, then the selected name
      --  identifies all declarations that are contained within the package
      --  or library denoted by the prefix of the selected name.
      --
      --  GHDL: therefore, the suffix must be either a package or a library.
      case Get_Kind (Prefix) is
         when Iir_Kind_Library_Declaration =>
            null;
         when Iir_Kind_Package_Instantiation_Declaration
           | Iir_Kind_Interface_Package_Declaration =>
            null;
         when Iir_Kind_Package_Declaration =>
            --  LRM08 12.4 Use clauses
            --  It is an error if the prefix of a selected name in a use
            --  clause denotes an uninstantiated package.
            if Is_Uninstantiated_Package (Prefix) then
               Error_Msg_Sem
                 (+Name_Prefix,
                  "use of uninstantiated package is not allowed");
               Set_Prefix (Name, Create_Error_Name (Name_Prefix));
               return;
            end if;
         when others =>
            Error_Msg_Sem
              (+Name, "prefix must designate a package or a library");
            Set_Prefix (Name, Create_Error_Name (Name_Prefix));
            return;
      end case;

      case Get_Kind (Name) is
         when Iir_Kind_Selected_Name =>
            Sem_Name (Name, True);
            case Get_Kind (Get_Named_Entity (Name)) is
               when Iir_Kind_Error =>
                  --  Continue in case of error.
                  null;
               when Iir_Kind_Overload_List =>
                  --  Analyze is correct as is.
                  null;
               when others =>
                  Name := Finish_Sem_Name (Name);
                  Set_Selected_Name (Clause, Name);
            end case;
         when Iir_Kind_Selected_By_All_Name =>
            null;
         when others =>
            raise Internal_Error;
      end case;
   end Sem_Use_Clause_Name;

   --  LRM 10.4  Use Clauses.
   procedure Sem_Use_Clause (Clauses: Iir_Use_Clause)
   is
      Clause : Iir_Use_Clause;
   begin
      Clause := Clauses;
      loop
         Sem_Use_Clause_Name (Clause);

         Clause := Get_Use_Clause_Chain (Clause);
         exit when Clause = Null_Iir;
      end loop;

      --  LRM 10.4
      --  For each use clause, there is a certain region of text called the
      --  scope of the use clause.  This region starts immediatly after the
      --  use clause.
      Sem_Scopes.Add_Use_Clause (Clauses);
   end Sem_Use_Clause;

   --  LRM 11.2  Design Libraries.
   procedure Sem_Library_Clause (Decl: Iir_Library_Clause)
   is
      Ident : Name_Id;
      Lib: Iir;
   begin
      --  GHDL: 'redeclaration' is handled in sem_scopes.

      Ident := Get_Identifier (Decl);
      Lib := Libraries.Get_Library (Ident, Get_Location (Decl));
      if Lib = Null_Iir then
         Error_Msg_Sem (+Decl, "no resource library %i", +Ident);
      else
         Set_Library_Declaration (Decl, Lib);
         Sem_Scopes.Add_Name (Lib, Ident, False);
         Set_Visible_Flag (Lib, True);

         --  Override the location of the library.  Even if the library is
         --  not really declared by the library clause (it is almost pre-
         --  declared), it improves error messages.
         --  Note: library clauses of dependences will overwrite the location,
         --   defeating the purpose of it.
         Location_Copy (Lib, Decl);

         Xref_Ref (Decl, Lib);
      end if;
   end Sem_Library_Clause;

   --  LRM08 13.4 Context clauses.
   procedure Sem_One_Context_Reference (Ref : Iir)
   is
      Name : Iir;
      Ent : Iir;
   begin
      Name := Get_Selected_Name (Ref);
      if Get_Kind (Name) /= Iir_Kind_Selected_Name then
         Error_Msg_Sem
           (+Name, "context reference only allows selected names");
         return;
      end if;

      Name := Sem_Denoting_Name (Name);
      Set_Selected_Name (Ref, Name);
      Ent := Get_Named_Entity (Name);
      if Is_Error (Ent) then
         return;
      end if;

      --  LRM08 13.4 Context clauses
      --  It is an error if a selected name in a context reference does not
      --  denote a context declaration.
      if Get_Kind (Ent) /= Iir_Kind_Context_Declaration then
         Error_Msg_Sem (+Name, "name must denote a context declaration");
         Set_Named_Entity (Name, Null_Iir);
         return;
      end if;
   end Sem_One_Context_Reference;

   --  LRM08 13.4 Context clauses.
   procedure Sem_Context_Reference (Ctxt : Iir)
   is
      Ref : Iir;
   begin
      Ref := Ctxt;
      loop
         Sem_One_Context_Reference (Ref);
         Ref := Get_Context_Reference_Chain (Ref);
         exit when Ref = Null_Iir;
      end loop;

      --  FIXME: must be done clause after clause ?
      Add_Context_Reference (Ctxt);
   end Sem_Context_Reference;

   --  LRM 11.3  Context Clauses.
   procedure Sem_Context_Clauses (Unit: Iir)
   is
      El: Iir;
   begin
      El := Get_Context_Items (Unit);
      while El /= Null_Iir loop
         case Get_Kind (El) is
            when Iir_Kind_Use_Clause =>
               Sem_Use_Clause (El);
            when Iir_Kind_Library_Clause =>
               Sem_Library_Clause (El);
            when Iir_Kind_Context_Reference =>
               Sem_Context_Reference (El);
            when others =>
               Error_Kind ("sem_context_clauses", El);
         end case;
         El := Get_Chain (El);
      end loop;
   end Sem_Context_Clauses;

   --  LRM08 13.3 Context declarations
   procedure Sem_Context_Declaration (Decl: Iir)
   is
      --  Return TRUE iff the first prefix of NAME denotes library WORK.
      function Has_Work_Library_Prefix (Name : Iir) return Boolean
      is
         Prefix : Iir;
      begin
         Prefix := Name;
         while Get_Kind (Prefix) = Iir_Kind_Selected_Name
           or else Get_Kind (Prefix) = Iir_Kind_Selected_By_All_Name
         loop
            Prefix := Get_Prefix (Prefix);
         end loop;
         return Get_Kind (Prefix) = Iir_Kind_Simple_Name
           and then Get_Identifier (Prefix) = Std_Names.Name_Work
           and then (Get_Kind (Get_Named_Entity (Prefix))
                       = Iir_Kind_Library_Declaration);
      end Has_Work_Library_Prefix;

      procedure Error_Work_Prefix (Loc : Iir) is
      begin
         Error_Msg_Sem
           (+Loc, "'work' not allowed as prefix in context declaration");
      end Error_Work_Prefix;

      El : Iir;
      El1 : Iir;
   begin
      Sem_Scopes.Add_Name (Decl);
      Xref_Decl (Decl);

      Sem_Context_Clauses (Decl);

      El := Get_Context_Items (Decl);
      while El /= Null_Iir loop
         case Get_Kind (El) is
            when Iir_Kind_Library_Clause =>
               --  LRM08 13.3 Context declarations
               --  It is an error if a library clause in a context declaration
               --  defines the library logical name WORK, [...]
               if Get_Identifier (El) = Std_Names.Name_Work then
                  Error_Msg_Sem
                    (+El, "'library work' not allowed in context declaration");
               end if;
            when Iir_Kind_Use_Clause =>
               --  LRM08 13.3 Context declarations
               --  [...] or if a selected name in a use clause [or a context
               --  reference] in a context declaration has the library logic
               --  name WORK as a prefix.
               El1 := El;
               while El1 /= Null_Iir loop
                  if Has_Work_Library_Prefix (Get_Selected_Name (El1)) then
                     Error_Work_Prefix (El1);
                     exit;
                  end if;
                  El1 := Get_Use_Clause_Chain (El1);
               end loop;
            when Iir_Kind_Context_Reference =>
               --  LRM08 13.3 Context declarations
               --  [...] or if a selected name in [a use clause or] a context
               --  reference in a context declaration has the library logic
               --  name WORK as a prefix.
               El1 := El;
               while El1 /= Null_Iir loop
                  if Has_Work_Library_Prefix (Get_Selected_Name (El1)) then
                     Error_Work_Prefix (El1);
                     exit;
                  end if;
                  El1 := Get_Context_Reference_Chain (El1);
               end loop;
            when others =>
               raise Internal_Error;
         end case;
         El := Get_Chain (El);
      end loop;

      --  GHDL: forbid self-reference by making declaration visible at the end.
      --  This violates LRM08 12.3 Visibility:  A declaration is visible only
      --  within a certain part of its scope; ...
      Set_Visible_Flag (Decl, True);
   end Sem_Context_Declaration;

   -- Access to the current design unit.  This is set, saved, restored, cleared
   -- by the procedure semantic.
   Current_Design_Unit: Iir_Design_Unit := Null_Iir;

   function Get_Current_Design_Unit return Iir_Design_Unit is
   begin
      return Current_Design_Unit;
   end Get_Current_Design_Unit;

   --  LRM 11.1  Design units.
   procedure Semantic (Design_Unit : Iir_Design_Unit)
   is
      Library_Unit : constant Iir := Get_Library_Unit (Design_Unit);
      Library : constant Iir := Get_Library (Get_Design_File (Design_Unit));
      Prev_Unit : Iir;
      Old_Design_Unit : Iir_Design_Unit;
      Implicit : Implicit_Declaration_Type;
   begin
      --  Sanity check: can analyze either previously analyzed unit or just
      --  parsed unit.
      case Get_Date (Design_Unit) is
         when Date_Parsed =>
            Set_Date (Design_Unit, Date_Analyzing);
         when Date_Valid =>
            null;
         when Date_Obsolete =>
            --  This happens only when design files are added into the library
            --  and keeping obsolete units (eg: to pretty print a file).
            Set_Date (Design_Unit, Date_Analyzing);
         when others =>
            raise Internal_Error;
      end case;

      --  If there is already a unit with the same name, mark it as being
      --  replaced.
      if Library_Unit /= Null_Iir then
         if Get_Kind (Library_Unit) in Iir_Kinds_Primary_Unit then
            Prev_Unit := Libraries.Find_Primary_Unit
              (Library, Get_Identifier (Library_Unit));
            if Is_Valid (Prev_Unit) and then Prev_Unit /= Design_Unit then
               Set_Date (Prev_Unit, Date_Replacing);
            end if;
         end if;
      end if;

      --  Save and set current_design_unit.
      Old_Design_Unit := Current_Design_Unit;
      Current_Design_Unit := Design_Unit;
      Push_Signals_Declarative_Part (Implicit, Null_Iir);

      --  Have a clean and empty state for scopes.
      Push_Interpretations;

      --  LRM02 10.1 Declarative Region.
      --  In addition to the above declarative region, there is a root
      --  declarative region, not associated with a portion of the text of the
      --  description, but encompassing any given primary unit.  At the
      --  beginning of the analysis of a given primary unit, there are no
      --  declarations whose scopes (see 10.2) are within the root declarative
      --  region.  Moreover, the root declarative region associated with any
      --  given secondary unit is the root declarative region of the
      --  corresponding primary unit.
      --  GHDL: for any revision of VHDL, a root declarative region is created,
      --    due to reasons given by LCS 3 (VHDL Issue # 1028).
      Open_Declarative_Region;

      --  LRM 11.2
      --  Every design unit is assumed to contain the following implicit
      --  context items as part of its context clause:
      --    library STD, WORK; use STD.STANDARD.all;
      Sem_Scopes.Add_Name (Libraries.Std_Library, Std_Names.Name_Std, False);
      Sem_Scopes.Add_Name (Library, Std_Names.Name_Work, False);
      Sem_Scopes.Use_All_Names (Standard_Package);

      --  Use pre-defined locations for STD and WORK library (as they may
      --  be later overridden).
      Set_Location (Libraries.Std_Library, Libraries.Library_Location);
      Set_Location (Library, Libraries.Library_Location);

      if Get_Dependence_List (Design_Unit) = Null_Iir_List then
         Set_Dependence_List (Design_Unit, Create_Iir_List);
      end if;
      Add_Dependence (Std_Standard_Unit);

      --  Analyze context clauses.
      Sem_Context_Clauses (Design_Unit);

      --  Analyze the library unit.
      if Library_Unit /= Null_Iir then
         --  Can be null_iir in case of parse error.
         case Iir_Kinds_Library_Unit (Get_Kind (Library_Unit)) is
            when Iir_Kind_Entity_Declaration =>
               Sem_Entity_Declaration (Library_Unit);
            when Iir_Kind_Architecture_Body =>
               Sem_Architecture_Body (Library_Unit);
            when Iir_Kind_Package_Declaration =>
               Sem_Package_Declaration (Library_Unit);
            when Iir_Kind_Package_Body =>
               Sem_Package_Body (Library_Unit);
            when Iir_Kind_Configuration_Declaration =>
               Sem_Configuration_Declaration (Library_Unit);
            when Iir_Kind_Package_Instantiation_Declaration =>
               Sem_Package_Instantiation_Declaration (Library_Unit);
            when Iir_Kind_Context_Declaration =>
               Sem_Context_Declaration (Library_Unit);
            when Iir_Kinds_Verification_Unit =>
               Sem_Psl.Sem_Psl_Verification_Unit (Library_Unit);
            when Iir_Kind_Foreign_Module =>
               raise Internal_Error;
         end case;
      end if;

      Close_Declarative_Region;

      Pop_Interpretations;

      if Get_Date (Design_Unit) = Date_Analyzing then
         Set_Date (Design_Unit, Date_Analyzed);
      end if;

      if Get_Analysis_Checks_List (Design_Unit) /= Null_Iir_List then
         Sem_Analysis_Checks_List (Design_Unit, False);
      end if;

      --  Restore current_design_unit.
      Current_Design_Unit := Old_Design_Unit;
      Pop_Signals_Declarative_Part (Implicit);
   end Semantic;
end Vhdl.Sem;
