arduino / arduino-cli

Arduino command line tool
https://arduino.github.io/arduino-cli/latest/
GNU General Public License v3.0
4.36k stars 382 forks source link

Generated function prototype injected before declaration of custom parameter type #2696

Open 6v6gt-duino opened 4 years ago

6v6gt-duino commented 4 years ago

Describe the problem

In order to make it easier for beginners to get started with writing Arduino sketches, and for the convenience of all users, Arduino CLI automatically generates and adds prototypes for functions defined in a .ino file of a sketch.

Under certain specific conditions, the function prototype is inserted into the code at a location before the declaration of a custom type referenced in the function signature.

🐛 The sketch compilation fails spuriously.

To reproduce

Setup environment

$ arduino-cli version

arduino-cli  Version: git-snapshot Commit: c5812eea6 Date: 2024-09-02T17:16:38Z

$ mkdir -P "/tmp/FooSketch"

$ printf '
void foo() {}  // This causes the prototype to be inserted before the declaration of `bar_t`
enum bar_t {};
void baz(bar_t qux) {
  (void)qux;  // Fix "unused parameter" warning
}
void setup() {}
void loop() {}
' > "/tmp/FooSketch/FooSketch.ino"

Demo

$ arduino-cli compile --fqbn arduino:avr:uno "/tmp/FooSketch"

C:\Users\per\AppData\Local\Temp\FooSketch\FooSketch.ino:4:10: error: variable or field 'baz' declared void
 void baz(bar_t qux) {
          ^~~~~
C:\Users\per\AppData\Local\Temp\FooSketch\FooSketch.ino:4:10: error: 'bar_t' was not declared in this scope

🐛 There was a spurious compilation failure of valid code.

By looking at the C++ code generated by the Arduino sketch preprocessor, we can see the cause of the error:

$ arduino-cli compile --fqbn arduino:avr:uno --preprocess "/tmp/FooSketch"

#include <Arduino.h>
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"

#line 2 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"
void foo();
#line 4 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"
void baz(bar_t qux);
#line 7 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"
void setup();
#line 8 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"
void loop();
#line 2 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"
void foo() {}  // This causes the prototype to be inserted before the declaration of `bar_t`
enum bar_t {};
void baz(bar_t qux) {
  (void)qux;  // Fix "unused parameter" warning
}
void setup() {}
void loop() {}

🐛 The spurious compilation failure was caused by Arduino CLI placing the prototype for the baz function before the declaration of the bar_t type.

Expected behavior

Generated function prototypes should be inserted after the declarations of types used in the function signature.

Arduino CLI version

Original report

Arduino IDE 1.8.13

Last verified with

c5812eea68afdb0e4e774f4f15ec4a34f0c3100c

Operating system

Operating system version

Additional context

Originally reported at https://forum.arduino.cc/t/weird-g-error-compiling-simple-type-definition/680759

Additional reports

Related

Workaround

Manually add a function prototype at the appropriate location:

void foo() {}
enum bar_t {};
void baz(bar_t qux);  // Manually added function prototype to workaround prototype generator bug.
void baz(bar_t qux) {
  (void)qux;  // Fix "unused parameter" warning
}
void setup() {}
void loop() {}

Issue checklist

facchinm commented 4 years ago

Hi @6v6gt-duino , thank for reporting! The issue lies in the prototype generator as you noticed. What bothers me is that both functions are already declared before their usage so the prototype generator shouldn't create anything. We'll investigate soon and report back

6v6gt-duino commented 3 years ago

Here is another link including a discussion of this issue and including additional error/test cases: https://forum.arduino.cc/index.php?topic=718515.0

sterretjeToo commented 1 year ago

This topic is now nearly 3 years old. The problem persists in IDE 2.1.1.

We'll investigate soon and report back

A concerned Arduino user ;)

6v6gt-duino commented 1 year ago

That gives me the opportunity of adding another example which has occurred in the meantime: https://forum.arduino.cc/t/is-the-location-of-a-global-function-important/996378

6v6gt-duino commented 2 months ago

Yet another one not seen before from: https://forum.arduino.cc/t/iram-attr-questions/1297715 : The initial assessment is that the storage qualifier IRAM_ATTR prevents the identification of second_sharp() as a function and hence no prototype is generated bit this is a guess. Shifting the function definition above setup() apparently works.

#define timepulse D3    //  1 nterrupt every second
volatile int affiche_flag = 0;
volatile int pps_cnt = 0;

void setup() {
  attachInterrupt(timepulse, second_sharp, RISING);
}

void IRAM_ATTR second_sharp() { // routine  d'interruption toute les secondes exactes
  affiche_flag = true; // debloque l'affichage
  pps_cnt = 0;
}

void loop() {
  if (affiche_flag) {
    affiche_flag = false;
    Serial.println("tick");
  }
}