Skip to content

Commit cf3d453

Browse files
committed
issue doxygen#11849 Incorrect evaluation of __VA_OPT__ when preprocessing
1 parent 532f998 commit cf3d453

File tree

1 file changed

+38
-25
lines changed

1 file changed

+38
-25
lines changed

src/pre.l

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,6 +2634,38 @@ static void skipCommentMacroName(yyscan_t yyscanner, const QCString &expr, QCStr
26342634
} while (changed);
26352635
}
26362636

2637+
// Expand C++20's __VA_OPT__(x) to either x if hasOptionalArgs==true or to the empty string if false
2638+
static QCString expandVAOpt(const QCString &vaStr,bool hasOptionalArgs)
2639+
{
2640+
QCString result;
2641+
int vo=0, vp=0;
2642+
result.clear();
2643+
int vl = static_cast<int>(vaStr.length());
2644+
while ((vo = vaStr.find("__VA_OPT__(",vp))!=-1)
2645+
{
2646+
result+=vaStr.left(vo);
2647+
int ve=vo+11; // skip over '__VA_OPT__(' part
2648+
int bc=1;
2649+
while (bc>0 && ve<vl)
2650+
{
2651+
if (vaStr[ve]==')') bc--;
2652+
else if (vaStr[ve]=='(') bc++;
2653+
ve++;
2654+
}
2655+
// ve points to end of __VA_OPT__(....)
2656+
if (bc==0 && hasOptionalArgs)
2657+
{
2658+
QCString voStr = vaStr.mid(vo+11,ve-vo-12);
2659+
//printf("vo=%d ve=%d voStr=%s\n",vo,ve,qPrint(voStr));
2660+
result+=voStr; // take 'x' from __VA_OPT__(x)
2661+
}
2662+
vp=ve;
2663+
}
2664+
result+=vaStr.mid(vp);
2665+
//printf("vaStr='%s'\n -> '%s'\n",qPrint(vaStr),qPrint(result));
2666+
return result;
2667+
}
2668+
26372669
/*! replaces the function macro \a def whose argument list starts at
26382670
* \a pos in expression \a expr.
26392671
* Notice that this routine may scan beyond the \a expr string if needed.
@@ -2643,6 +2675,7 @@ static void skipCommentMacroName(yyscan_t yyscanner, const QCString &expr, QCStr
26432675
*/
26442676
static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result,int level)
26452677
{
2678+
//YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
26462679
//printf(">replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s') level=%zu\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),state->levelGuard.size());
26472680
uint32_t j=pos;
26482681
len=0;
@@ -2678,7 +2711,7 @@ static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCStrin
26782711
else
26792712
{
26802713
while (!done && (argCount<def->nargs || def->varArgs) &&
2681-
((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2714+
((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
26822715
)
26832716
{
26842717
char c=(char)cc;
@@ -2708,7 +2741,9 @@ static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCStrin
27082741
arg+=c;
27092742
}
27102743
else
2744+
{
27112745
arg+=c;
2746+
}
27122747
}
27132748
}
27142749
else if (c==')' || c==',') // last or next argument found
@@ -2796,7 +2831,8 @@ static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCStrin
27962831
uint32_t k=0;
27972832
// substitution of all formal arguments
27982833
QCString resExpr;
2799-
const QCString d=def->definition.stripWhiteSpace();
2834+
QCString d=def->definition.stripWhiteSpace();
2835+
if (def->varArgs) d = expandVAOpt(d,argCount!=def->nargs-1);
28002836
//printf("Macro definition: '%s'\n",qPrint(d));
28012837
bool inString=FALSE;
28022838
while (k<d.length())
@@ -3047,29 +3083,6 @@ static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,in
30473083
//printf(" <<<< call replaceFunctionMacro: replaced=%d\n",replaced);
30483084
len+=l;
30493085
}
3050-
else if (macroName=="__VA_OPT__")
3051-
{
3052-
// expr='( something __VA_OPT__(value) )' or '( something __VA_OPT__(value) something_else )'
3053-
static const reg::Ex re(R"(__VA_OPT__\((.*)\)(.*)\))");
3054-
reg::Match m;
3055-
std::string s = expr.mid(p).str();
3056-
if (reg::search(s,m,re))
3057-
{
3058-
assert(m.size()==3);
3059-
std::string value = m[1].str();
3060-
std::string remainder = m[2].str();
3061-
//printf("value='%s' remainder='%s'\n",qPrint(value),qPrint(remainder));
3062-
expMacro = stripWhiteSpace(remainder).empty() ? std::string() : value;
3063-
expanded=true;
3064-
replaced=true;
3065-
len+=l+2+m[1].str().length();
3066-
}
3067-
else
3068-
{
3069-
//printf("no match for '%s'\n",qPrint(expr));
3070-
}
3071-
}
3072-
//printf(" macroName='%s' expMacro='%s' replaced=%d expanded=%d\n",qPrint(macroName),qPrint(expMacro),replaced,expanded);
30733086

30743087
if (replaced) // expand the macro and rescan the expression
30753088
{

0 commit comments

Comments
 (0)