Semantic checking (The GNU Modula-2 Compiler)

### 2.9 How to detect run time problems at compile time ¶

Consider the following program:

    MODULE assignvalue ;  (*!m2iso+gm2*)

    PROCEDURE bad () : INTEGER ;
    VAR
       i: INTEGER ;
    BEGIN
       i := -1 ;
       RETURN i
    END bad ;

    VAR
       foo: CARDINAL ;
    BEGIN
       (* The m2rte plugin will detect this as an error, post
          optimization.  *)
       foo := bad ()
    END assignvalue.

here we see that the programmer has overlooked that the return value from ‘`bad`’ will cause an overflow to ‘`foo`’. If we compile the code with the following options:

    $ gm2 -g -fsoft-check-all -O2 -fm2-plugin -c assignvalue.mod
    assignvalue.mod:16:0:inevitable that this error will occur at run time,
    assignment will result in an overflow

The gm2 semantic plugin is automatically run and will generate a warning message for every exception call which is known as reachable. It is highly advised to run the optimizer (‘`-O2`’ or ‘`-O3`’) with ‘`-fsoft-check-all`’ so that the compiler is able to run the optimizer and perform variable and flow analysis before the semantic plugin is invoked.

The ‘`-Wuninit-variable-checking`’ can be used to identify uninitialized variables within the first basic block in a procedure. The checking is limited to variables so long as they are not an array or set or a variant record or var parameter.

The following example detects whether a sub component within a record is uninitialized.

    MODULE testlarge2 ;

    TYPE
       color = RECORD
                  r, g, b: CARDINAL ;
               END ;

       pixel = RECORD
                  fg, bg: color ;
               END ;

    PROCEDURE test ;
    VAR
       p: pixel ;
    BEGIN
       p.fg.r := 1 ;
       p.fg.g := 2 ;
       p.fg.g := 3 ;   (* Deliberate typo should be p.fg.b.  *)
       p.bg := p.fg ;  (* Accessing an uninitialized field.  *)
    END test ;

    BEGIN
       test
    END testlarge2.

    $ gm2 -c -Wuninit-variable-checking testlarge2.mod
    testlarge2.mod:19:13: warning: In procedure ‘test’: attempting to
    access expression before it has been initialized
       19 |    p.bg := p.fg ;  (* Accessing an uninitialized field.  *)
          |            ~^~~

The following example detects if an individual field is uninitialized.

    MODULE testwithnoptr ;

    TYPE
       Vec =  RECORD
                 x, y: CARDINAL ;
              END ;

    PROCEDURE test ;
    VAR
       p: Vec ;
    BEGIN
       WITH p DO
          x := 1 ;
          x := 2   (* Deliberate typo, user meant y.  *)
       END ;
       IF p.y = 2
       THEN
       END
    END test ;

    BEGIN
       test
    END testwithnoptr.

The following example detects a record is uninitialized via a pointer variable in a ‘`WITH`’ block.

    $ gm2 -g -c -Wuninit-variable-checking testwithnoptr.mod
    testwithnoptr.mod:21:8: warning: In procedure ‘test’: attempting to
    access expression before it has been initialized
       21 |    IF p.y = 2
          |       ~^~

    MODULE testnew6 ;

    FROM Storage IMPORT ALLOCATE ;

    TYPE
       PtrToVec = POINTER TO RECORD
                                x, y: INTEGER ;
                             END ;

    PROCEDURE test ;
    VAR
       p: PtrToVec ;
    BEGIN
       NEW (p) ;
       WITH p^ DO
          x := 1 ;
          x := 2   (* Deliberate typo, user meant y.  *)
       END ;
       IF p^.y = 2
       THEN
       END
    END test ;

    BEGIN
       test
    END testnew6.

    $ gm2 -g -c -Wuninit-variable-checking testnew6.mod
    testnew6.mod:19:9: warning: In procedure ‘test’: attempting to
    access expression before it has been initialized
       19 |    IF p^.y = 2
          |       ~~^~