Browse Source

fcl-passrc: resolver: allow for for-loop var only local vars

mattias 3 years ago
parent
commit
6c98a63285

+ 2 - 0
packages/fcl-passrc/src/pasresolveeval.pas

@@ -209,6 +209,7 @@ const
   nDirectiveXNotAllowedHere = 3143;
   nDirectiveXNotAllowedHere = 3143;
   nAwaitWithoutPromise = 3144;
   nAwaitWithoutPromise = 3144;
   nSymbolCannotBeExportedFromALibrary = 3145;
   nSymbolCannotBeExportedFromALibrary = 3145;
+  nForLoopControlVarMustBeSimpleLocalVar = 3146;
 
 
   // using same IDs as FPC
   // using same IDs as FPC
   nVirtualMethodXHasLowerVisibility = 3250; // was 3050
   nVirtualMethodXHasLowerVisibility = 3250; // was 3050
@@ -365,6 +366,7 @@ resourcestring
   sDirectiveXNotAllowedHere = 'Directive "%s" not allowed here';
   sDirectiveXNotAllowedHere = 'Directive "%s" not allowed here';
   sAwaitWithoutPromise = 'Await without promise';
   sAwaitWithoutPromise = 'Await without promise';
   sSymbolCannotBeExportedFromALibrary = 'The symbol cannot be exported from a library';
   sSymbolCannotBeExportedFromALibrary = 'The symbol cannot be exported from a library';
+  sForLoopControlVarMustBeSimpleLocalVar = 'For loop control variable must be simple local variable';
 
 
 type
 type
   { TResolveData - base class for data stored in TPasElement.CustomData }
   { TResolveData - base class for data stored in TPasElement.CustomData }

+ 14 - 0
packages/fcl-passrc/src/pasresolver.pp

@@ -7577,6 +7577,7 @@ var
   bt: TResolverBaseType;
   bt: TResolverBaseType;
   TypeEl, ElType: TPasType;
   TypeEl, ElType: TPasType;
   C: TClass;
   C: TClass;
+  IdentEl: TPasElement;
 begin
 begin
   CreateScope(Loop,TPasForLoopScope);
   CreateScope(Loop,TPasForLoopScope);
 
 
@@ -7585,6 +7586,19 @@ begin
   ComputeElement(Loop.VariableName,VarResolved,[rcNoImplicitProc,rcSetReferenceFlags]);
   ComputeElement(Loop.VariableName,VarResolved,[rcNoImplicitProc,rcSetReferenceFlags]);
   if not ResolvedElCanBeVarParam(VarResolved,Loop.VariableName) then
   if not ResolvedElCanBeVarParam(VarResolved,Loop.VariableName) then
     RaiseVarExpected(20170216151955,Loop.VariableName,VarResolved.IdentEl);
     RaiseVarExpected(20170216151955,Loop.VariableName,VarResolved.IdentEl);
+  IdentEl:=VarResolved.IdentEl;
+  C:=IdentEl.ClassType;
+  if (C=TPasArgument)
+    or (C=TPasResultElement)
+    or ((C=TPasVariable) and ((IdentEl.Parent is TProcedureBody) or (IdentEl.Parent is TPasSection))) then
+    // loop var is simple local var
+  else
+    begin
+    {$IFDEF VerbosePasResolver}
+    writeln('TPasResolver.FinishForLoopHeader ',GetResolverResultDbg(VarResolved),' IdentEl=',GetObjPath(IdentEl));
+    {$ENDIF}
+    RaiseMsg(20220815164902,nForLoopControlVarMustBeSimpleLocalVar,sForLoopControlVarMustBeSimpleLocalVar,[],Loop.VariableName);
+    end;
 
 
   // resolve start expression
   // resolve start expression
   ResolveExpr(Loop.StartExpr,rraRead);
   ResolveExpr(Loop.StartExpr,rraRead);

+ 20 - 0
packages/fcl-passrc/tests/tcresolver.pas

@@ -329,6 +329,7 @@ type
     Procedure TestForLoop_NestedSameVarFail;
     Procedure TestForLoop_NestedSameVarFail;
     Procedure TestForLoop_AssignVarFail;
     Procedure TestForLoop_AssignVarFail;
     Procedure TestForLoop_PassVarFail;
     Procedure TestForLoop_PassVarFail;
+    Procedure TestForLoop_FieldFail;
     Procedure TestStatements;
     Procedure TestStatements;
     Procedure TestCaseOfInt;
     Procedure TestCaseOfInt;
     Procedure TestCaseOfIntExtConst;
     Procedure TestCaseOfIntExtConst;
@@ -5187,6 +5188,25 @@ begin
   CheckResolverException('Illegal assignment to for-loop variable "i"',nIllegalAssignmentToForLoopVar);
   CheckResolverException('Illegal assignment to for-loop variable "i"',nIllegalAssignmentToForLoopVar);
 end;
 end;
 
 
+procedure TTestResolver.TestForLoop_FieldFail;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    Size: word;',
+  '    procedure Fly;',
+  '  end;',
+  'procedure TObject.Fly;',
+  'begin',
+  '  for Size:=1 to 2 do',
+  '    ;',
+  'end;',
+  'begin',
+  '']);
+  CheckResolverException(sForLoopControlVarMustBeSimpleLocalVar,nForLoopControlVarMustBeSimpleLocalVar);
+end;
+
 procedure TTestResolver.TestStatements;
 procedure TTestResolver.TestStatements;
 begin
 begin
   StartProgram(false);
   StartProgram(false);