Merge pull request #2761 from kugelfuhr/kugelfuhr/fix-2231

Allow comments within _Pragma()
This commit is contained in:
Bob Andrews
2025-07-03 18:36:43 +02:00
committed by GitHub
4 changed files with 83 additions and 63 deletions

View File

@@ -48,6 +48,7 @@
#include "error.h" #include "error.h"
#include "global.h" #include "global.h"
#include "litpool.h" #include "litpool.h"
#include "preproc.h"
#include "scanner.h" #include "scanner.h"
#include "scanstrbuf.h" #include "scanstrbuf.h"
#include "symtab.h" #include "symtab.h"
@@ -866,24 +867,18 @@ static void NoteMessagePragma (const char* Message)
static void ParsePragmaString (void) static void ParsePragmaString (StrBuf* B)
/* Parse the contents of _Pragma */ /* Parse the contents of _Pragma */
{ {
pragma_t Pragma; pragma_t Pragma;
StrBuf Ident = AUTO_STRBUF_INITIALIZER; StrBuf Ident = AUTO_STRBUF_INITIALIZER;
/* Create a string buffer from the string literal */
StrBuf B = AUTO_STRBUF_INITIALIZER;
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
/* Skip the string token */ /* Skip the string token */
NextToken (); NextToken ();
/* Get the pragma name from the string */ /* Get the pragma name from the string */
SB_SkipWhite (&B); SB_SkipWhite (B);
if (!SB_GetSym (&B, &Ident, "-")) { if (!SB_GetSym (B, &Ident, "-")) {
Error ("Invalid pragma"); Error ("Invalid pragma");
goto ExitPoint; goto ExitPoint;
} }
@@ -903,119 +898,119 @@ static void ParsePragmaString (void)
} }
/* Check for an open paren */ /* Check for an open paren */
SB_SkipWhite (&B); SB_SkipWhite (B);
if (SB_Get (&B) != '(') { if (SB_Get (B) != '(') {
Error ("'(' expected"); Error ("'(' expected");
goto ExitPoint; goto ExitPoint;
} }
/* Skip white space before the argument */ /* Skip white space before the argument */
SB_SkipWhite (&B); SB_SkipWhite (B);
/* Switch for the different pragmas */ /* Switch for the different pragmas */
switch (Pragma) { switch (Pragma) {
case PRAGMA_ALIGN: case PRAGMA_ALIGN:
/* TODO: PES_EXPR (PES_DECL) */ /* TODO: PES_EXPR (PES_DECL) */
IntPragma (PES_STMT, Pragma, &B, &DataAlignment, 1, 4096); IntPragma (PES_STMT, Pragma, B, &DataAlignment, 1, 4096);
break; break;
case PRAGMA_ALLOW_EAGER_INLINE: case PRAGMA_ALLOW_EAGER_INLINE:
FlagPragma (PES_STMT, Pragma, &B, &EagerlyInlineFuncs); FlagPragma (PES_STMT, Pragma, B, &EagerlyInlineFuncs);
break; break;
case PRAGMA_BSS_NAME: case PRAGMA_BSS_NAME:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */ /* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
SegNamePragma (PES_FUNC, PRAGMA_BSS_NAME, &B); SegNamePragma (PES_FUNC, PRAGMA_BSS_NAME, B);
break; break;
case PRAGMA_CHARMAP: case PRAGMA_CHARMAP:
CharMapPragma (PES_IMM, &B); CharMapPragma (PES_IMM, B);
break; break;
case PRAGMA_CHECK_STACK: case PRAGMA_CHECK_STACK:
/* TODO: PES_SCOPE maybe? */ /* TODO: PES_SCOPE maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &CheckStack); FlagPragma (PES_FUNC, Pragma, B, &CheckStack);
break; break;
case PRAGMA_CODE_NAME: case PRAGMA_CODE_NAME:
/* PES_FUNC is the only sensible option so far */ /* PES_FUNC is the only sensible option so far */
SegNamePragma (PES_FUNC, PRAGMA_CODE_NAME, &B); SegNamePragma (PES_FUNC, PRAGMA_CODE_NAME, B);
break; break;
case PRAGMA_CODESIZE: case PRAGMA_CODESIZE:
/* PES_EXPR would be optimization nightmare */ /* PES_EXPR would be optimization nightmare */
IntPragma (PES_STMT, Pragma, &B, &CodeSizeFactor, 10, 1000); IntPragma (PES_STMT, Pragma, B, &CodeSizeFactor, 10, 1000);
break; break;
case PRAGMA_DATA_NAME: case PRAGMA_DATA_NAME:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */ /* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
SegNamePragma (PES_FUNC, PRAGMA_DATA_NAME, &B); SegNamePragma (PES_FUNC, PRAGMA_DATA_NAME, B);
break; break;
case PRAGMA_INLINE_STDFUNCS: case PRAGMA_INLINE_STDFUNCS:
/* TODO: PES_EXPR maybe? */ /* TODO: PES_EXPR maybe? */
FlagPragma (PES_STMT, Pragma, &B, &InlineStdFuncs); FlagPragma (PES_STMT, Pragma, B, &InlineStdFuncs);
break; break;
case PRAGMA_LOCAL_STRINGS: case PRAGMA_LOCAL_STRINGS:
/* TODO: PES_STMT or even PES_EXPR */ /* TODO: PES_STMT or even PES_EXPR */
FlagPragma (PES_FUNC, Pragma, &B, &LocalStrings); FlagPragma (PES_FUNC, Pragma, B, &LocalStrings);
break; break;
case PRAGMA_MESSAGE: case PRAGMA_MESSAGE:
/* PES_IMM is the only sensible option */ /* PES_IMM is the only sensible option */
StringPragma (PES_IMM, &B, NoteMessagePragma); StringPragma (PES_IMM, B, NoteMessagePragma);
break; break;
case PRAGMA_OPTIMIZE: case PRAGMA_OPTIMIZE:
/* TODO: PES_STMT or even PES_EXPR maybe? */ /* TODO: PES_STMT or even PES_EXPR maybe? */
FlagPragma (PES_STMT, Pragma, &B, &Optimize); FlagPragma (PES_STMT, Pragma, B, &Optimize);
break; break;
case PRAGMA_REGVARADDR: case PRAGMA_REGVARADDR:
/* TODO: PES_STMT or even PES_EXPR maybe? */ /* TODO: PES_STMT or even PES_EXPR maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &AllowRegVarAddr); FlagPragma (PES_FUNC, Pragma, B, &AllowRegVarAddr);
break; break;
case PRAGMA_REGISTER_VARS: case PRAGMA_REGISTER_VARS:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */ /* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &EnableRegVars); FlagPragma (PES_FUNC, Pragma, B, &EnableRegVars);
break; break;
case PRAGMA_RODATA_NAME: case PRAGMA_RODATA_NAME:
/* TODO: PES_STMT or even PES_EXPR maybe? */ /* TODO: PES_STMT or even PES_EXPR maybe? */
SegNamePragma (PES_FUNC, PRAGMA_RODATA_NAME, &B); SegNamePragma (PES_FUNC, PRAGMA_RODATA_NAME, B);
break; break;
case PRAGMA_SIGNED_CHARS: case PRAGMA_SIGNED_CHARS:
/* TODO: PES_STMT or even PES_EXPR maybe? */ /* TODO: PES_STMT or even PES_EXPR maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &SignedChars); FlagPragma (PES_FUNC, Pragma, B, &SignedChars);
break; break;
case PRAGMA_STATIC_LOCALS: case PRAGMA_STATIC_LOCALS:
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */ /* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &StaticLocals); FlagPragma (PES_FUNC, Pragma, B, &StaticLocals);
break; break;
case PRAGMA_WRAPPED_CALL: case PRAGMA_WRAPPED_CALL:
/* PES_IMM is the only sensible option */ /* PES_IMM is the only sensible option */
WrappedCallPragma (PES_IMM, &B); WrappedCallPragma (PES_IMM, B);
break; break;
case PRAGMA_WARN: case PRAGMA_WARN:
/* PES_IMM is the only sensible option */ /* PES_IMM is the only sensible option */
WarnPragma (PES_IMM, &B); WarnPragma (PES_IMM, B);
break; break;
case PRAGMA_WRITABLE_STRINGS: case PRAGMA_WRITABLE_STRINGS:
/* TODO: PES_STMT or even PES_EXPR maybe? */ /* TODO: PES_STMT or even PES_EXPR maybe? */
FlagPragma (PES_FUNC, Pragma, &B, &WritableStrings); FlagPragma (PES_FUNC, Pragma, B, &WritableStrings);
break; break;
case PRAGMA_ZPSYM: case PRAGMA_ZPSYM:
/* PES_IMM is the only sensible option */ /* PES_IMM is the only sensible option */
StringPragma (PES_IMM, &B, MakeZPSym); StringPragma (PES_IMM, B, MakeZPSym);
break; break;
default: default:
@@ -1023,27 +1018,26 @@ static void ParsePragmaString (void)
} }
/* Closing paren expected */ /* Closing paren expected */
SB_SkipWhite (&B); SB_SkipWhite (B);
if (SB_Get (&B) != ')') { if (SB_Get (B) != ')') {
Error ("')' expected"); Error ("')' expected");
goto ExitPoint; goto ExitPoint;
} }
SB_SkipWhite (&B); SB_SkipWhite (B);
/* Allow an optional semicolon to be compatible with the old syntax */ /* Allow an optional semicolon to be compatible with the old syntax */
if (SB_Peek (&B) == ';') { if (SB_Peek (B) == ';') {
SB_Skip (&B); SB_Skip (B);
SB_SkipWhite (&B); SB_SkipWhite (B);
} }
/* Make sure nothing follows */ /* Make sure nothing follows */
if (SB_Peek (&B) != '\0') { if (SB_Peek (B) != '\0') {
Error ("Unexpected input following pragma directive"); Error ("Unexpected input following pragma directive");
} }
ExitPoint: ExitPoint:
/* Release the string buffers */ /* Release the string buffers */
SB_Done (&B);
SB_Done (&Ident); SB_Done (&Ident);
} }
@@ -1082,8 +1076,24 @@ void ConsumePragma (void)
*/ */
PragmaErrorSkip (); PragmaErrorSkip ();
} else { } else {
/* Pragmas that have the C99 _Pragma operator in the source code
** (instead of #pragma that was converted to _Pragma by the
** preprocessor) have the argument not preprocessed. We need to do
** that here, since it may contain comments. Weird but legal C. Pragmas
** that were converted from #pragma are already preprocessed but doing
** it twice won't harm.
*/
StrBuf In = AUTO_STRBUF_INITIALIZER;
StrBuf Out = AUTO_STRBUF_INITIALIZER;
SB_Append (&In, GetLiteralStrBuf (CurTok.SVal));
TranslationPhase3 (&In, &Out);
SB_Done (&In);
/* Parse the pragma */ /* Parse the pragma */
ParsePragmaString (); ParsePragmaString (&Out);
/* Free the string buffer */
SB_Done (&Out);
} }
--InPragmaParser; --InPragmaParser;

View File

@@ -157,11 +157,6 @@ struct HiddenMacro {
static void TranslationPhase3 (StrBuf* Source, StrBuf* Target);
/* Mimic Translation Phase 3. Handle old and new style comments. Collapse
** non-newline whitespace sequences.
*/
static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags); static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags);
/* Preprocess a single line. Handle specified tokens and operators, remove /* Preprocess a single line. Handle specified tokens and operators, remove
** whitespace and comments, then do macro replacement. ** whitespace and comments, then do macro replacement.
@@ -3338,7 +3333,22 @@ void HandleSpecialMacro (Macro* M, const char* Name)
static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags)
/* Preprocess a single line. Handle specified tokens and operators, remove
** whitespace and comments, then do macro replacement.
*/
{
MacroExp E;
SkipWhitespace (0);
InitMacroExp (&E);
ReplaceMacros (Source, Target, &E, ModeFlags | MSM_IN_DIRECTIVE);
DoneMacroExp (&E);
}
void TranslationPhase3 (StrBuf* Source, StrBuf* Target)
/* Mimic Translation Phase 3. Handle old and new style comments. Collapse /* Mimic Translation Phase 3. Handle old and new style comments. Collapse
** non-newline whitespace sequences. ** non-newline whitespace sequences.
*/ */
@@ -3384,21 +3394,6 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target)
static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags)
/* Preprocess a single line. Handle specified tokens and operators, remove
** whitespace and comments, then do macro replacement.
*/
{
MacroExp E;
SkipWhitespace (0);
InitMacroExp (&E);
ReplaceMacros (Source, Target, &E, ModeFlags | MSM_IN_DIRECTIVE);
DoneMacroExp (&E);
}
void Preprocess (void) void Preprocess (void)
/* Preprocess lines count of which is affected by directives */ /* Preprocess lines count of which is affected by directives */
{ {

View File

@@ -68,6 +68,11 @@ struct IFile;
void HandleSpecialMacro (Macro* M, const char* Name); void HandleSpecialMacro (Macro* M, const char* Name);
/* Handle special "magic" macros that may change */ /* Handle special "magic" macros that may change */
void TranslationPhase3 (StrBuf* Source, StrBuf* Target);
/* Mimic Translation Phase 3. Handle old and new style comments. Collapse
** non-newline whitespace sequences.
*/
void Preprocess (void); void Preprocess (void);
/* Preprocess a line */ /* Preprocess a line */

10
test/val/bug2231.c Normal file
View File

@@ -0,0 +1,10 @@
_Pragma("message/*Comment1*/ ( /*Comment2*/\"test message\" /*Comment3*/)")
/* We have no pragma without parenthesis but if there would be one, the
** following should also work:
*/
/* _Pragma("once// Comment") */
int main(void)
{
return 0;
}