https://gcc.gnu.org/g:b48823919cb0b5ed481568896c8cd9963402a681

commit r17-5735-gb48823919cb0b5ed481568896c8cd9963402a681
Author: Jose E. Marchesi <[email protected]>
Date:   Thu Oct 29 10:12:08 2026 +0100

    a68: fix operator dispatch for standenv exponentiation
    
    In find_operator, after doing a search_table_chain_for_operator for
    dyadic opeators there is C.2, C.3 and C.4, which (to my understanding)
    are intended to implement the standard operators described in
    10.2.3.5.a, 10.2.3.5.b, 10.2.3.5.c and 10.2.3.5.d without having to
    enumerate every real/int combination ("cross-term"):
    
      a) op P = (L real a, L int b) L real: a P L real(b);
      b) op P = (L int a, L real b) L real: L real(a) P b;
      c) op R = (L real a, L int b) bool: a R L real(b);
      d) op R = (L int a, L real b) bool: L real(a) R b;
    
    However, there is also:
    
      g) op <^,**,UP> = (L real a, int b) L real: ...;
    
    And that case, for pow, should _not_ be submitted to the cross-term
    expansion or this invalid code will be admitted:
    
      LONG 3.14      ^ LONG 2
      LONG LONG 3.14 ^ LONG LONG 2
    
    With the second operands being (incorrectly) widened, which is not
    allowed in a strong context.
    
    The fix is a bit ugly because it relies in the representation of the
    standard pow operators, but it works.
    
    Signed-off-by: Jose E. Marchesi <[email protected]>
    
    gcc/algol68/ChangeLog
    
            * a68-parser-moids-check.cc (find_operator): Do not apply shortcut
            for cross real/int definitions to exponentiation.
    
    gcc/testsuite/ChangeLog
    
            * algol68/execute/pow-real-1.a68: Update test.
            * algol68/compile/pow-long-long-real-long-long-int-1.a68: New
            test.
            * algol68/compile/pow-long-real-long-int-1.a68: Likewise.

Diff:
---
 gcc/algol68/a68-parser-moids-check.cc                             | 8 ++++++++
 .../algol68/compile/pow-long-long-real-long-long-int-1.a68        | 2 ++
 gcc/testsuite/algol68/compile/pow-long-real-long-int-1.a68        | 3 +++
 gcc/testsuite/algol68/execute/pow-real-1.a68                      | 4 ++--
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/gcc/algol68/a68-parser-moids-check.cc 
b/gcc/algol68/a68-parser-moids-check.cc
index 92e0e3f7c8be..7f61cec97829 100644
--- a/gcc/algol68/a68-parser-moids-check.cc
+++ b/gcc/algol68/a68-parser-moids-check.cc
@@ -1014,6 +1014,12 @@ find_operator (TABLE_T *s, const char *n, MOID_T *x, 
MOID_T *y)
   z = search_table_chain_for_operator (s, n, x, y);
   if (z != NO_TAG)
     return z;
+
+  /* The checks below apply to operators covered by a) and b) in 10.2.3.5 but
+     not to the pow operator, which is covered by g) */
+  if (strcmp (n, "**") == 0 || strcmp (n, "^") == 0)
+    return z;
+
   /* (C.2) Vector and matrix "strong coercions" in standard environ.  */
   u = DEFLEX (a68_depref_completely (x));
   v = DEFLEX (a68_depref_completely (y));
@@ -1053,6 +1059,7 @@ find_operator (TABLE_T *s, const char *n, MOID_T *x, 
MOID_T *y)
            return z;
        }
     }
+
   /* (C.3) Look in standenv for an appropriate cross-term.  */
   u = a68_make_series_from_moids (x, y);
   u = a68_make_united_mode (u);
@@ -1109,6 +1116,7 @@ find_operator (TABLE_T *s, const char *n, MOID_T *x, 
MOID_T *y)
   z = search_table_for_operator (OPERATORS (A68_STANDENV), n, v, v);
   if (z != NO_TAG)
     return z;
+
   return NO_TAG;
 }
 
diff --git 
a/gcc/testsuite/algol68/compile/pow-long-long-real-long-long-int-1.a68 
b/gcc/testsuite/algol68/compile/pow-long-long-real-long-long-int-1.a68
new file mode 100644
index 000000000000..910dc23d9b62
--- /dev/null
+++ b/gcc/testsuite/algol68/compile/pow-long-long-real-long-long-int-1.a68
@@ -0,0 +1,2 @@
+begin long long 3.14 ** long long 20 { dg-error "has not been declared" }
+end
diff --git a/gcc/testsuite/algol68/compile/pow-long-real-long-int-1.a68 
b/gcc/testsuite/algol68/compile/pow-long-real-long-int-1.a68
new file mode 100644
index 000000000000..e6c2d46d75d3
--- /dev/null
+++ b/gcc/testsuite/algol68/compile/pow-long-real-long-int-1.a68
@@ -0,0 +1,3 @@
+begin 10 * 3.14;
+      long 3.14 ** long 20 { dg-error "has not been declared" }
+end
diff --git a/gcc/testsuite/algol68/execute/pow-real-1.a68 
b/gcc/testsuite/algol68/execute/pow-real-1.a68
index de8de77093f7..826d00000d32 100644
--- a/gcc/testsuite/algol68/execute/pow-real-1.a68
+++ b/gcc/testsuite/algol68/execute/pow-real-1.a68
@@ -3,7 +3,7 @@ BEGIN REAL r0 = 2.0; LONG REAL rr0 = LONG 2.0; LONG LONG REAL 
rrr0 = LONG LONG 2
       REAL r1 = r0 ^ 2; REAL r2 = r0 ^ 3.0;
       WORD REAL w0 = WORD 2.0;
       WORD REAL w1 = w0 ^ 2; WORD REAL w2 = w0 ^ WORD 3.0;
-      LONG REAL rr1 = rr0 ^ LONG 2; LONG REAL rr2 = rr0 ^ LONG 3.0;
-      LONG LONG REAL rrr1 = rrr0 ^ LONG LONG 2; LONG LONG REAL rrr2 = rrr0 ^ 
LONG LONG 3.0;
+      LONG REAL rr1 = rr0 ^ 2; LONG REAL rr2 = rr0 ^ LONG 3.0;
+      LONG LONG REAL rrr1 = rrr0 ^ 2; LONG LONG REAL rrr2 = rrr0 ^ LONG LONG 
3.0;
       SKIP
 END

Reply via email to