Compliation error that makes no sense

Here's something inconceivable to me. The following code does not compile successfully. Even more mind numbingly, if I bring the struct definition to the top, it will compile successfully. What's going on?

void my_function() {}

struct thingy {};

void my_other_function(thingy& g) {}

void setup() {}

void loop() {}
/private/var/folders/f3/kzndkbp54vg3qcyh1dzht7xc0000gn/T/.arduinoIDE-unsaved2026822-74067-1cnttt4.vgb3/sketch_sep22b/sketch_sep22b.ino:5:6: error: variable or field 'my_other_function' declared void
    5 | void my_other_function(thingy& g) {}
      |      ^~~~~~~~~~~~~~~~~
/private/var/folders/f3/kzndkbp54vg3qcyh1dzht7xc0000gn/T/.arduinoIDE-unsaved2026822-74067-1cnttt4.vgb3/sketch_sep22b/sketch_sep22b.ino:5:24: error: 'thingy' was not declared in this scope
    5 | void my_other_function(thingy& g) {}
      |                        ^~~~~~
/private/var/folders/f3/kzndkbp54vg3qcyh1dzht7xc0000gn/T/.arduinoIDE-unsaved2026822-74067-1cnttt4.vgb3/sketch_sep22b/sketch_sep22b.ino:5:32: error: 'g' was not declared in this scope
    5 | void my_other_function(thingy& g) {}
      |                                ^
exit status 1

Hi @chippylongstocking. The Arduino sketch build system does something called "sketch preprocessing". This makes some minor modifications to the "Arduino language" sketch code of the .ino files of your sketch to convert the code to valid C++, which is then passed to a standard C++ compiler.

One of those changes is adding function prototypes for all functions that don't already have one.

Here is what your sketch code looks like after sketch preprocessing:

#include <Arduino.h>
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026822-52368-dmrzzb.doa16\\sketch_sep22b\\sketch_sep22b.ino"
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026822-52368-dmrzzb.doa16\\sketch_sep22b\\sketch_sep22b.ino"
void my_function();
#line 5 "C:\\Users\\per\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026822-52368-dmrzzb.doa16\\sketch_sep22b\\sketch_sep22b.ino"
void my_other_function(thingy& g);
#line 7 "C:\\Users\\per\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026822-52368-dmrzzb.doa16\\sketch_sep22b\\sketch_sep22b.ino"
void setup();
#line 9 "C:\\Users\\per\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026822-52368-dmrzzb.doa16\\sketch_sep22b\\sketch_sep22b.ino"
void loop();
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026822-52368-dmrzzb.doa16\\sketch_sep22b\\sketch_sep22b.ino"
void my_function() {}

struct thingy {};

void my_other_function(thingy& g) {}

void setup() {}

void loop() {}

Note the prototype for my_other_function:

void my_other_function(thingy& g);

has been inserted above the declaration of the thingy struct. This is the cause of the error. The error message is a bit confusing because it is about code that doesn't exist in the Arduino IDE sketch editor.

The workaround for this is to manually add the function prototype to the correct location in the sketch:

void my_function() {}

struct thingy {};

void my_other_function(thingy& g);

void my_other_function(thingy& g) {}

void setup() {}

void loop() {}

The sketch preprocessor only generates prototypes for functions that don't already have one. So manually adding one will cause the preprocessor to skip adding a prototype for my_other_function.

This is the problem, I guess.

I can't image why I'd have to explain to any professional developer why extremely simple and valid code not compiling and producing an unhelpful error message is a problem for everyone, so if you're reading this and you're in a position to fix this, please do. It's absurd and infuriating. The fact that this seemingly has persisted for years doesn't give me faith in this platform.

Thanks for taking the time to respond. I'll go with the workaround and get on with my life, but this really isn't good behavior for the IDE.

IS that legal? “Thingy” isn’t a type, it’s just a Struct variable. Shouldn’t you have:

void my_other_function(struct thingy& g);

(Could be a C vs C++ thing…)

I think for C you are correct, I haven't written C in ages.

Arduino programming traps, tips and style guide - Gammon Forum look for "Trap #30: Being tricked by the IDE preprocessor" - it is age old problem with Arduino IDE (came from Arduino style "don't be afraid, we are not programming, we are just scratching").
(Also read all other traps, it is good to avoid them in projects. Yes, you probabelly know lot of them already.)

This bug exists for a long time. See e.g. Generated function prototype injected before declaration of custom parameter type · Issue #2696 · arduino/arduino-cli · GitHub which is soon having it's 6th birthday and Weird g++ error compiling simple type definition.

Your chances that somebody in the Arduino company will fix it are very slim.