@@ -31,7 +31,9 @@ use crate::ast::{
3131 SensitivityList , SequentialStatement , SignalAttribute , UnitId , UnitKey , Waveform , WithRef ,
3232} ;
3333use crate :: data:: { DiagnosticHandler , ErrorCode , Symbol } ;
34- use crate :: { Config , Diagnostic , EntityId , HasTokenSpan , SrcPos , TokenAccess , TokenSpan } ;
34+ use crate :: {
35+ AnyEntKind , Config , Diagnostic , EntityId , HasTokenSpan , SrcPos , TokenAccess , TokenSpan ,
36+ } ;
3537use fnv:: FnvHashMap ;
3638use itertools:: Itertools ;
3739use std:: collections:: hash_map:: Entry ;
@@ -590,19 +592,33 @@ fn is_likely_clocked(root: &DesignRoot, expression: &Expression) -> bool {
590592 attribute. attr . item == AttributeDesignator :: Signal ( SignalAttribute :: Event )
591593 }
592594 Name :: CallOrIndexed ( coi) => {
593- if let Some ( reference) = coi. name . item . get_suffix_reference ( ) {
594- let ent = root. get_ent ( reference) ;
595- if let Some ( library_name) = ent. library_name ( ) {
596- if ( library_name. name_utf8 ( ) . to_lowercase ( ) == "ieee"
597- || library_name. name_utf8 ( ) . to_lowercase ( ) == "std" )
598- && ( ent. designator . to_string ( ) . to_lowercase ( ) == "rising_edge"
599- || ent. designator . to_string ( ) . to_lowercase ( ) == "falling_edge" )
600- {
601- return true ;
595+ let Some ( reference) = coi. name . item . get_suffix_reference ( ) else {
596+ return false ;
597+ } ;
598+ let ent = root. get_ent ( reference) ;
599+ match ent. kind ( ) {
600+ // Any function that has one argument and returns `boolean`
601+ // is considered clocked.
602+ // This is true, for example, for the standard
603+ // RISING_EDGE(signal S: BOOLEAN) return BOOLEAN; and
604+ // FALLING_EDGE(signal S: BOOLEAN) return BOOLEAN;
605+ // functions.
606+ AnyEntKind :: Overloaded ( ovl) => {
607+ // FIXME: This check could include check for a function
608+ // Currently, checks functions, procedures and other miscellaneous items
609+ let signature = ovl. signature ( ) ;
610+ if signature. formals . len ( ) != 1 {
611+ return false ;
602612 }
613+ let Some ( ret_type) = signature. return_type else {
614+ return false ;
615+ } ;
616+ // FIXME: This should probably check that `ret_type` is the actual boolean type
617+ // and not the std boolean type
618+ ret_type. designator == Designator :: Identifier ( root. symbol_utf8 ( "BOOLEAN" ) )
603619 }
620+ _ => false ,
604621 }
605- false
606622 }
607623 _ => false ,
608624 } ,
@@ -847,4 +863,53 @@ end architecture;",
847863 let _ = root. search ( & mut searcher) ;
848864 assert_eq ! ( idx. get( ) , 9 ) ;
849865 }
866+
867+ // GitHub issue: 378
868+ #[ test]
869+ fn check_generic_clk_edge ( ) {
870+ let mut builder = LibraryBuilder :: new ( ) ;
871+
872+ builder. code (
873+ "libname" ,
874+ "
875+ library ieee;
876+ use ieee.std_logic_1164.all;
877+
878+ entity generic_clk_edge_function_warning is
879+ generic (
880+ function active_edge(signal s: std_ulogic) return boolean
881+ );
882+ port (
883+ clk: in std_ulogic;
884+ data_out: out std_ulogic
885+ );
886+ end entity;
887+
888+ architecture behavioural of generic_clk_edge_function_warning is
889+ signal internal_signal: std_ulogic := '0';
890+ begin
891+ process (clk)
892+ begin
893+ if active_edge(clk) then -- Trigger: function call via generic
894+ internal_signal <= not internal_signal;
895+ end if;
896+ end process;
897+
898+ data_out <= internal_signal;
899+ end architecture;" ,
900+ ) ;
901+
902+ builder. add_std_logic_1164 ( ) ;
903+ let ( root, diagnostics) = builder. get_analyzed_root ( ) ;
904+ check_no_diagnostics ( & diagnostics) ;
905+
906+ let num_of_searches = Cell :: new ( 0 ) ;
907+ let mut searcher = ProcessSearcher :: new ( |proc, ctx| {
908+ num_of_searches. set ( num_of_searches. get ( ) + 1 ) ;
909+ let diag = lint_sensitivity_list ( & root, ctx, proc) ;
910+ assert_eq ! ( diag, Vec :: default ( ) ) ;
911+ } ) ;
912+ let _ = root. search ( & mut searcher) ;
913+ assert_eq ! ( num_of_searches. get( ) , 1 )
914+ }
850915}
0 commit comments