Constant function used to set parameters

We use a lot of constant functions in our code to setup parameters/localparams. This has worked quite nicely to setup our code, and works with multiple tools.
However, a new tool is choking on some of this logic, and the vendor is claiming that our usage is non-standard compliant. An example:

module foo1;

// Constant function1
function integer fun1( input integer a );
  return( a + 1 );
endfunction

// Constant function2
function integer fun2( input integer b );
  return( fun1( b + 1 ) );
endfunction

localparam VAL1 = 20;
localparam VAL2 = fun1( VAL1 );	 // Constant function of a constant
localparam VAL3 = fun2( VAL1 );  // Constant function, of a constant function of a constant.

$info( "VAL1 = %0d, VAL2 = %0d, VAL3 = %0d", VAL1, VAL2, VAL3 );

endmodule

The claim is the assignment to VAL2 is valid, but VAL3 is not. From the 1800-2012 standard, section 13.4.3:

Constant functions shall not themselves use constant functions in any context requiring a constant
expression.

Is my new vendor accurate in the assessement of the standard? This a rather restrictive constraint - allowing only one level of constant function at elaboration?

In reply to Mark Curry:

The call to fun1 inside fun2 is not being used in a context requiring fun1 to be a constant function. I think it is legal. This is an example of a place where a call to fun1 is required to be a constant function

function integer fun4( input [fun1(2):0]  b );
  return b;
endfunction

In the call to fun1() inside the definition of fun4(), fun1 must be a constant function. If I just have

initial $display(fun4(22);

That would be OK because fun4 is not being used as a constant function. but if I have

localparam VAL4 = fun4(22);

This is the case that the LRM prohibits.

Hi Dave (or any other gurus). I have a similar issue that Xcelium is complaining about. Here’s the simplified version:

module my_mod 
  #(parameter type D_IN_T) 
   (input D_IN_TYPE d_in); // a value of type D_IN_T

   typedef type (d_in) SAME_AS_D_IN_T;  	// ok
   localparam	D_IN_BITS = $bits(d_in); 	// ok
   localparam string D_IN_T_STR = $typename (d_in);
   //                                     |
   // ERROR!!! Illegal non-local reference to constant function [10.3.5(IEEE)].
endmodule : my_mod

Why isn’t $typename considered a constant function? I’m looking at section 20.6.1 of the 1800-2017 and don’t see anything indicating that it can’t be used as a contant.
Section 11.2.1 has this:

Certain built-in system functions where the arguments are constant expressions are constant system function
calls. Specifically, these are the conversion system functions listed in 20.5, the mathematical system
functions listed in 20.8, and the bit vector system functions listed in 20.9.
The data query system functions listed in 20.6 and the array query system functions listed in 20.7 are
normally also constant system function calls even when their arguments are not constant. See those
subclauses for the conditions under which these query system function calls are considered to be constant
expressions.

$typename is part of 20.6. The only reference to constants in this section is this:

When used as an elaboration time constant, the expression shall not contain any
hierarchical references or references to elements of dynamic objects.

As opposed to 20.5 which has this:

These conversion system functions may be used in constant expressions, as specified in 11.2.1.

Does this imply that $typename can’t be used? I even tried this so I was sure the argument was a constant but got the same error:

localparam string D_IN_T_STR = $typename (logic [7:0]);

Can you give any clarification?

What I’m actually trying to do is have a module where d_in can be unsigned integer, signed integer, or real (and maybe string) and process it appropriately. Assuming there’s no way around this issue with $typename, is there some other way of extracting this info?
The module already calls a static function from a virtual class so that I can parameterize it. That part works fine.

Thanks!!!