Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CPreProcessor: support variadic macros with GNU cpp extension syntax #4184

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Units/parser-cxx.r/complex-macros.d/args.ctags
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
-D DECLARE_FUNCTION_2(_ret,_name)=_ret _name();
-D DECLARE_FUNCTION_3(_ret,_name,...)=_ret _name(__VA_ARGS__);
-D DEPRECATED(...)=__VA_ARGS__ __attribute__((deprecated))
-D ENUM_GNUX(n,e...)=enum n { e }
-D DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2)=DECLARE_FUNCTION_2(int,_prefix1 ## a) DECLARE_FUNCTION_2(int,_prefix2 ## a)
-D STRINGIFY(token)=#token
-D IMPLEMENT_FUNCTIONS(_prefix)=void _prefix ## a(){ }; void _prefix ## b(){ };
Expand Down
7 changes: 7 additions & 0 deletions Units/parser-cxx.r/complex-macros.d/expected.tags
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ a input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" z prototype:p3 typeref
b input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" z prototype:p3 typeref:typename:int file:
DEPRECATED input.cpp /^#define DEPRECATED(/;" d file: signature:(...)
p4 input.cpp /^DEPRECATED(int p4());$/;" p typeref:typename:int file: signature:() properties:deprecated
n input.cpp /^#define ENUM_GNUX(n,e...) enum n { e }$/;" D macro:ENUM_GNUX
e input.cpp /^#define ENUM_GNUX(n,e...) enum n { e }$/;" D macro:ENUM_GNUX
ENUM_GNUX input.cpp /^#define ENUM_GNUX(/;" d file: signature:(n,e...)
color input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" g file:
red input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" e enum:color file:
blue input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" e enum:color file:
green input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" e enum:color file:
_prefix1 input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \\$/;" D macro:DECLARE_TWO_VERSIONS_OF_FUNCTIONS
_prefix2 input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \\$/;" D macro:DECLARE_TWO_VERSIONS_OF_FUNCTIONS
DECLARE_TWO_VERSIONS_OF_FUNCTIONS input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(/;" d file: signature:(_prefix1,_prefix2)
Expand Down
4 changes: 4 additions & 0 deletions Units/parser-cxx.r/complex-macros.d/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ DECLARE_FUNCTION_3(int,p3,int a,int b);

DEPRECATED(int p4());

#define ENUM_GNUX(n,e...) enum n { e }

ENUM_GNUX(color, red, blue, green);

// Recursive macro expansion

#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \
Expand Down
45 changes: 39 additions & 6 deletions parsers/cpreprocessor.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,12 @@ static int externalParserBlockNestLevel;
*/
static bool BraceFormat = false;

void cppPushExternalParserBlock(void)
extern void cppPushExternalParserBlock(void)
{
externalParserBlockNestLevel++;
}

void cppPopExternalParserBlock(void)
extern void cppPopExternalParserBlock(void)
{
externalParserBlockNestLevel--;
}
Expand Down Expand Up @@ -527,13 +527,13 @@ extern void cppUngetc (const int c)
Cpp.ungetDataSize++;
}

int cppUngetBufferSize(void)
extern int cppUngetBufferSize(void)
{
return Cpp.ungetBufferSize;
}

/* This puts an entire string back into the input queue for the input File. */
void cppUngetString(const char * string,int len)
extern void cppUngetString(const char * string,int len)
{
if(!string)
return;
Expand Down Expand Up @@ -985,7 +985,28 @@ static int directiveDefine (const int c, bool undef)

if (vStringLength (param) > 0)
{
int r = makeParamTag (param, nth++, vStringChar(param, 0) == '.');
bool gnuext_placeholder = false;
if (vStringLength (param) > 3
&& strcmp(vStringValue (param) + vStringLength (param) - 3,
"...") == 0)
{
/* args... in GNU cpp extension
*
* #define debug(format, args...) fprintf (stderr, format, args)
*
* In this case, args should be tagged. However the signature field
* for debug must be "(format,args...)".
*/
vString *nodots = vStringNewNInit (vStringValue (param),
vStringLength (param) - 3);
makeParamTag (nodots, nth, false);
vStringDelete (nodots);
gnuext_placeholder = true;
}

int r = makeParamTag (param, nth++,
vStringChar(param, 0) == '.'
|| gnuext_placeholder);
intArrayAdd (params, r);
vStringClear (param);
}
Expand Down Expand Up @@ -1346,7 +1367,7 @@ static int skipOverDComment (void)
return c;
}

const vString * cppGetLastCharOrStringContents (void)
extern const vString * cppGetLastCharOrStringContents (void)
{
CXX_DEBUG_ASSERT(Cpp.charOrStringContents,"Shouldn't be called when CPP is not initialized");
return Cpp.charOrStringContents;
Expand Down Expand Up @@ -2410,13 +2431,25 @@ static cppMacroInfo * saveMacro(hashTable *table, const char * macro)

if(
(
/* #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__) */
bIsVarArg &&
(paramLen == 3) &&
(strncmp(paramBegin[i],"...",3) == 0)
) || (
/* #define debug(MSG) fputs(MSG, stderr) */
(!bIsVarArg) &&
(paramLen == tokenLen) &&
(strncmp(paramBegin[i],tokenBegin,paramLen) == 0)
) || (
/* GNU cpp extension:
* #define debug(format, args...) fprintf (stderr, format, args)
*/
(!bIsVarArg) &&
(paramLen == tokenLen + 3) &&
(strncmp(paramBegin[i] + tokenLen, "...", 3) == 0) &&
(strncmp(paramBegin[i], tokenBegin, tokenLen) == 0) &&
/* Let's have a side effect */
(bIsVarArg = true)
)
)
{
Expand Down
Loading