mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Use musttail attribute to guarantee tail recursion (#1849)
This commit is contained in:
@@ -60,4 +60,13 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// gcc and clang have their own `musttail` attributes for tail recursion
|
||||||
|
#if defined(__clang__) && __has_cpp_attribute(clang::musttail)
|
||||||
|
#define MUSTTAIL [[clang::musttail]]
|
||||||
|
#elif defined(__GNUC__) && __has_cpp_attribute(gnu::musttail)
|
||||||
|
#define MUSTTAIL [[gnu::musttail]]
|
||||||
|
#else
|
||||||
|
#define MUSTTAIL
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RGBDS_PLATFORM_HPP
|
#endif // RGBDS_PLATFORM_HPP
|
||||||
|
|||||||
@@ -744,7 +744,7 @@ static int peek() {
|
|||||||
lexerState->expansionScanDistance += str->length();
|
lexerState->expansionScanDistance += str->length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return peek(); // Tail recursion
|
MUSTTAIL return peek();
|
||||||
} else if (c == '{') {
|
} else if (c == '{') {
|
||||||
// If character is an open brace, do symbol interpolation
|
// If character is an open brace, do symbol interpolation
|
||||||
shiftChar();
|
shiftChar();
|
||||||
@@ -752,7 +752,7 @@ static int peek() {
|
|||||||
beginExpansion(interp.second, interp.first->name);
|
beginExpansion(interp.second, interp.first->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return peek(); // Tail recursion
|
MUSTTAIL return peek();
|
||||||
} else {
|
} else {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -1695,7 +1695,7 @@ static Token yylex_NORMAL() {
|
|||||||
return Token(nextToken);
|
return Token(nextToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;; lexerState->atLineStart = false) {
|
for (;;) {
|
||||||
int c = bumpChar();
|
int c = bumpChar();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
@@ -1707,7 +1707,7 @@ static Token yylex_NORMAL() {
|
|||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
// Handle unambiguous single-char tokens
|
// Handle unambiguous single-char tokens
|
||||||
|
|
||||||
@@ -1759,7 +1759,7 @@ static Token yylex_NORMAL() {
|
|||||||
if (peek() == '*') {
|
if (peek() == '*') {
|
||||||
shiftChar();
|
shiftChar();
|
||||||
discardBlockComment();
|
discardBlockComment();
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
return oneOrTwo('=', T_(POP_DIVEQ), T_(OP_DIV));
|
return oneOrTwo('=', T_(POP_DIVEQ), T_(OP_DIV));
|
||||||
|
|
||||||
@@ -1897,7 +1897,7 @@ static Token yylex_NORMAL() {
|
|||||||
// Macro args were handled by `peek`, and character escapes do not exist
|
// Macro args were handled by `peek`, and character escapes do not exist
|
||||||
// outside of string literals, so this must be a line continuation.
|
// outside of string literals, so this must be a line continuation.
|
||||||
discardLineContinuation();
|
discardLineContinuation();
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
// Handle raw strings... or fall through if '#' is not followed by '"'
|
// Handle raw strings... or fall through if '#' is not followed by '"'
|
||||||
|
|
||||||
@@ -1918,7 +1918,7 @@ static Token yylex_NORMAL() {
|
|||||||
c = bumpChar();
|
c = bumpChar();
|
||||||
} else if (!startsIdentifier(c)) {
|
} else if (!startsIdentifier(c)) {
|
||||||
reportGarbageCharacters(c);
|
reportGarbageCharacters(c);
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token token = readIdentifier(c, raw);
|
Token token = readIdentifier(c, raw);
|
||||||
@@ -1943,7 +1943,9 @@ static Token yylex_NORMAL() {
|
|||||||
if (Symbol const *sym = sym_FindExactSymbol(std::get<std::string>(token.value));
|
if (Symbol const *sym = sym_FindExactSymbol(std::get<std::string>(token.value));
|
||||||
sym && sym->type == SYM_EQUS) {
|
sym && sym->type == SYM_EQUS) {
|
||||||
beginExpansion(sym->getEqus(), sym->name);
|
beginExpansion(sym->getEqus(), sym->name);
|
||||||
return yylex_NORMAL(); // Tail recursion
|
// We cannot do `MUSTTAIL return yylex_NORMAL();` because tail call optimization
|
||||||
|
// requires the return value to be "trivially destructible", and `Token` is not.
|
||||||
|
continue; // Restart, reading from the new buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1968,6 +1970,10 @@ static Token yylex_NORMAL() {
|
|||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we exited the switch, i.e. read some characters without yet returning a token,
|
||||||
|
// we can't be at the start of the line
|
||||||
|
lexerState->atLineStart = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "itertools.hpp"
|
#include "itertools.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
#include "platform.hpp" // MUSTTAIL
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
|
|
||||||
#include "link/main.hpp"
|
#include "link/main.hpp"
|
||||||
@@ -203,7 +204,7 @@ static std::optional<size_t> getPlacement(Section const §ion, MemoryLocation
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getPlacement(section, location); // Tail recursion
|
MUSTTAIL return getPlacement(section, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getSectionDescription(Section const §ion) {
|
static std::string getSectionDescription(Section const §ion) {
|
||||||
|
|||||||
Reference in New Issue
Block a user