Skip to content

Commit 7be5461

Browse files
author
Gaius Mulley
committed
PR modula2/118589 Opaque type fields are visible outside implementation module
This patch fixes a bug shown when a variable declared as an opaque type is dereferenced outside the declaration module. The fix also improves error recovery. In the error cases it ensures that an error symbol is created and the appropriate virtual token is assigned. Finally there is a new testsuite directory gm2.dg which contains tests to check against expected error messages. gcc/m2/ChangeLog: PR modula2/118589 * gm2-compiler/M2MetaError.mod (symDesc): Add opaque type description. * gm2-compiler/M2Quads.mod (BuildDesignatorPointerError): New procedure. (BuildDesignatorPointer): Reimplement. * gm2-compiler/P3Build.bnf (SubDesignator): Tidy up error message. Use MetaErrorT2 rather than WriteForma1 and use the token pos from the quad stack. gcc/testsuite/ChangeLog: PR modula2/118589 * lib/gm2-dg.exp (gm2.exp): load_lib. * gm2.dg/pim/fail/badopaque.mod: New test. * gm2.dg/pim/fail/badopaque2.mod: New test. * gm2.dg/pim/fail/dg-pim-fail.exp: New test. * gm2.dg/pim/fail/opaquedefs.def: New test. * gm2.dg/pim/fail/opaquedefs.mod: New test. Signed-off-by: Gaius Mulley <[email protected]>
1 parent 12b7220 commit 7be5461

File tree

9 files changed

+157
-35
lines changed

9 files changed

+157
-35
lines changed

gcc/m2/gm2-compiler/M2MetaError.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,12 @@ BEGIN
16111611
END
16121612
ELSIF IsType(sym)
16131613
THEN
1614-
RETURN InitString('type')
1614+
IF IsHiddenType (sym)
1615+
THEN
1616+
RETURN InitString('opaque type')
1617+
ELSE
1618+
RETURN InitString('type')
1619+
END
16151620
ELSIF IsRecord(sym)
16161621
THEN
16171622
RETURN InitString('record')

gcc/m2/gm2-compiler/M2Quads.mod

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown,
6363
GetScope, GetCurrentScope,
6464
GetSubrange, SkipTypeAndSubrange,
6565
GetModule, GetMainModule,
66+
GetModuleScope, GetCurrentModuleScope,
6667
GetCurrentModule, GetFileModule, GetLocalSym,
6768
GetStringLength, GetString,
6869
GetArraySubscript, GetDimension,
@@ -115,7 +116,7 @@ FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown,
115116
PutDeclared,
116117
MakeComponentRecord, MakeComponentRef,
117118
IsSubscript, IsComponent, IsConstStringKnown,
118-
IsTemporary,
119+
IsTemporary, IsHiddenType,
119120
IsAModula2Type,
120121
PutLeftValueFrontBackType,
121122
PushSize, PushValue, PopValue,
@@ -11427,6 +11428,24 @@ BEGIN
1142711428
END BuildDesignatorError ;
1142811429

1142911430

11431+
(*
11432+
BuildDesignatorPointerError - removes the designator from the stack and replaces
11433+
it with an error symbol.
11434+
*)
11435+
11436+
PROCEDURE BuildDesignatorPointerError (type, rw: CARDINAL; tokpos: CARDINAL;
11437+
message: ARRAY OF CHAR) ;
11438+
VAR
11439+
error: CARDINAL ;
11440+
BEGIN
11441+
error := MakeError (tokpos, MakeKey (message)) ;
11442+
IF GetSType (type) # NulSym
11443+
THEN
11444+
type := GetSType (type)
11445+
END ;
11446+
PushTFrwtok (error, type, rw, tokpos)
11447+
END BuildDesignatorPointerError ;
11448+
1143011449

1143111450
(*
1143211451
BuildDesignatorArray - Builds the array referencing.
@@ -11819,13 +11838,13 @@ END DebugLocation ;
1181911838
PROCEDURE BuildDesignatorPointer (ptrtok: CARDINAL) ;
1182011839
VAR
1182111840
combinedtok,
11822-
exprtok : CARDINAL ;
11841+
destok : CARDINAL ;
1182311842
rw,
1182411843
Sym1, Type1,
1182511844
Sym2, Type2: CARDINAL ;
1182611845
BEGIN
11827-
PopTFrwtok (Sym1, Type1, rw, exprtok) ;
11828-
DebugLocation (exprtok, "expression") ;
11846+
PopTFrwtok (Sym1, Type1, rw, destok) ;
11847+
DebugLocation (destok, "des ptr expression") ;
1182911848

1183011849
Type1 := SkipType (Type1) ;
1183111850
IF Type1 = NulSym
@@ -11834,33 +11853,44 @@ BEGIN
1183411853
ELSIF IsUnknown (Sym1)
1183511854
THEN
1183611855
MetaError1 ('{%1EMad} is undefined and therefore {%1ad}^ cannot be resolved', Sym1)
11837-
ELSIF IsPointer (Type1)
11838-
THEN
11839-
Type2 := GetSType (Type1) ;
11840-
Sym2 := MakeTemporary (ptrtok, LeftValue) ;
11841-
(*
11842-
Ok must reference by address
11843-
- but we contain the type of the referenced entity
11844-
*)
11845-
MarkAsRead (rw) ;
11846-
PutVarPointerCheck (Sym1, TRUE) ;
11847-
CheckPointerThroughNil (ptrtok, Sym1) ;
11848-
IF GetMode (Sym1) = LeftValue
11849-
THEN
11850-
rw := NulSym ;
11851-
PutLeftValueFrontBackType (Sym2, Type2, Type1) ;
11852-
GenQuadO (ptrtok, IndrXOp, Sym2, Type1, Sym1, FALSE) (* Sym2 := *Sym1 *)
11853-
ELSE
11854-
PutLeftValueFrontBackType (Sym2, Type2, NulSym) ;
11855-
GenQuadO (ptrtok, BecomesOp, Sym2, NulSym, Sym1, FALSE) (* Sym2 := Sym1 *)
11856-
END ;
11857-
PutVarPointerCheck (Sym2, TRUE) ; (* we should check this for *)
11858-
(* Sym2 later on (pointer via NIL) *)
11859-
combinedtok := MakeVirtualTok (exprtok, exprtok, ptrtok) ;
11860-
PushTFrwtok (Sym2, Type2, rw, combinedtok) ;
11861-
DebugLocation (combinedtok, "pointer expression")
1186211856
ELSE
11863-
MetaError2 ('{%1ad} is not a pointer type but a {%2d}', Sym1, Type1)
11857+
combinedtok := MakeVirtual2Tok (destok, ptrtok) ;
11858+
IF IsPointer (Type1)
11859+
THEN
11860+
Type2 := GetSType (Type1) ;
11861+
Sym2 := MakeTemporary (ptrtok, LeftValue) ;
11862+
(*
11863+
Ok must reference by address
11864+
- but we contain the type of the referenced entity
11865+
*)
11866+
MarkAsRead (rw) ;
11867+
PutVarPointerCheck (Sym1, TRUE) ;
11868+
CheckPointerThroughNil (ptrtok, Sym1) ;
11869+
IF GetMode (Sym1) = LeftValue
11870+
THEN
11871+
rw := NulSym ;
11872+
PutLeftValueFrontBackType (Sym2, Type2, Type1) ;
11873+
GenQuadO (ptrtok, IndrXOp, Sym2, Type1, Sym1, FALSE) (* Sym2 := *Sym1. *)
11874+
ELSE
11875+
PutLeftValueFrontBackType (Sym2, Type2, NulSym) ;
11876+
GenQuadO (ptrtok, BecomesOp, Sym2, NulSym, Sym1, FALSE) (* Sym2 := Sym1. *)
11877+
END ;
11878+
(* We should check this for Sym2 later on (pointer via NIL). *)
11879+
PutVarPointerCheck (Sym2, TRUE) ;
11880+
PushTFrwtok (Sym2, Type2, rw, combinedtok) ;
11881+
DebugLocation (combinedtok, "pointer expression")
11882+
ELSIF IsHiddenType (Type1) AND (GetModuleScope (Type1) # GetCurrentModuleScope ())
11883+
THEN
11884+
MetaErrorT1 (ptrtok,
11885+
'{%1Ead} is declared with an opaque type from a different module and cannot be dereferenced',
11886+
Sym1) ;
11887+
MarkAsRead (rw) ;
11888+
BuildDesignatorPointerError (Type1, rw, combinedtok, 'bad opaque pointer dereference')
11889+
ELSE
11890+
MetaError2 ('{%1Ead} is not a pointer type but a {%2d}', Sym1, Type1) ;
11891+
MarkAsRead (rw) ;
11892+
BuildDesignatorPointerError (Type1, rw, combinedtok, 'bad pointer dereference')
11893+
END
1186411894
END
1186511895
END BuildDesignatorPointer ;
1186611896

gcc/m2/gm2-compiler/P3Build.bnf

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ FROM DynamicStrings IMPORT String, InitString, KillString, Mark, ConCat, ConCatC
5454
FROM M2Printf IMPORT printf0, printf1 ;
5555
FROM M2Debug IMPORT Assert ;
5656
FROM P2SymBuild IMPORT BuildString, BuildNumber ;
57-
FROM M2MetaError IMPORT MetaErrorT0 ;
57+
FROM M2MetaError IMPORT MetaErrorT0, MetaErrorT2 ;
5858
FROM M2CaseList IMPORT ElseCase ;
5959

6060
FROM M2Reserved IMPORT tokToTok, toktype,
@@ -1085,15 +1085,14 @@ SubDesignator := "." % VAR
10851085
n1 := GetSymName(Sym) ;
10861086
IF IsModuleKnown(GetSymName(Sym))
10871087
THEN
1088-
WriteFormat2('%a looks like a module which has not been globally imported (eg. suggest that you IMPORT %a ;)',
1088+
WriteFormat2('%a looks like a module which has not been globally imported (eg. suggest that you IMPORT %a)',
10891089
n1, n1)
10901090
ELSE
10911091
WriteFormat1('%a is not a record variable', n1)
10921092
END
10931093
ELSIF NOT IsRecord(Type)
10941094
THEN
1095-
n1 := GetSymName(Type) ;
1096-
WriteFormat1('%a is not a record type', n1)
1095+
MetaErrorT2 (tok, "the type of {%1ad} is not a record (but {%2ad}) and therefore it has no field", Sym, Type) ;
10971096
END ;
10981097
StartScope(Type) %
10991098
Ident
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
(* { dg-do compile } *)
3+
(* { dg-options "-g" } *)
4+
5+
MODULE badopaque ;
6+
7+
FROM opaquedefs IMPORT OpaqueA ;
8+
9+
VAR
10+
a: OpaqueA ;
11+
c: CARDINAL ;
12+
BEGIN
13+
c := 123 ;
14+
a^ := c (* { dg-error "with an opaque type" } *)
15+
END badopaque.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
(* { dg-do compile } *)
3+
(* { dg-options "-g" } *)
4+
5+
MODULE badopaque2 ;
6+
7+
FROM opaquedefs IMPORT OpaqueB ;
8+
9+
VAR
10+
b: OpaqueB ;
11+
c: CARDINAL ;
12+
BEGIN
13+
c := 123 ;
14+
b^.width := c (* { dg-bogus "unnamed" } *)
15+
(* { dg-error "cannot be dereferenced" "b^.width" { target *-*-* } 14 } *)
16+
(* { dg-error "has no field" "no field" { target *-*-* } 14 } *)
17+
END badopaque2.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright (C) 2025 Free Software Foundation, Inc.
2+
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with GCC; see the file COPYING3. If not see
15+
# <http://www.gnu.org/licenses/>.
16+
17+
# Compile tests, no torture testing.
18+
#
19+
# These tests raise errors in the front end; torture testing doesn't apply.
20+
21+
# Load support procs.
22+
load_lib gm2-dg.exp
23+
24+
gm2_init_pim4 $srcdir/$subdir
25+
26+
# Initialize `dg'.
27+
dg-init
28+
29+
# Main loop.
30+
31+
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] "" ""
32+
33+
# All done.
34+
dg-finish
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
DEFINITION MODULE opaquedefs ;
2+
3+
TYPE
4+
OpaqueA ;
5+
OpaqueB ;
6+
7+
END opaquedefs.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(* { dg-do compile } *)
2+
(* { dg-options "-g -c" } *)
3+
4+
IMPLEMENTATION MODULE opaquedefs ;
5+
6+
TYPE
7+
OpaqueA = POINTER TO CARDINAL ;
8+
OpaqueB = POINTER TO RECORD
9+
width : CARDINAL ;
10+
height: CARDINAL ;
11+
END ;
12+
13+
END opaquedefs.

gcc/testsuite/lib/gm2-dg.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# <http://www.gnu.org/licenses/>.
1616

1717
load_lib gcc-dg.exp
18+
load_lib gm2.exp
1819

1920
# Define gm2 callbacks for dg.exp.
2021

@@ -75,3 +76,4 @@ proc gm2-dg-runtest { testcases flags default-extra-flags } {
7576
}
7677
}
7778
}
79+

0 commit comments

Comments
 (0)