<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/68370>68370</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
RecursiveASTVisitor (RAV) visits default argument expressions multiple times if shouldVisitImplicitCode()
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
smcpeak
</td>
</tr>
</table>
<pre>
The documentation for [`RecursiveASTVisitor`](https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html#details) (RAV) says:
> By default, this visitor tries to visit every part of the explicit source code exactly once.
The meaning of this statement is not entirely clear to me ("by default"? "tries to"? "explicit"?), but I (perhaps simplistically) interpret it as implying that RAV should not visit any AST node more than once.
However, if `shouldVisitImplicitCode()` returns `true`, it will do just that for the case of default argument expressions, which it visits once for the declaration that establishes the default argument, and again for each use (uses are encapsulated in the [`CXXDefaultArgExpr`](https://clang.llvm.org/doxygen/classclang_1_1CXXDefaultArgExpr.html) node).
For example, with this input:
```c++
int makeInt();
void f1(int x = makeInt());
void f2()
{
f1();
f1();
}
```
If I write a libtooling program that first uses the text AST dumper, then runs a `RecursiveASTVisitor` that prints the address of every visited `Stmt` node:
```c++
class PrintVisited : public clang::RecursiveASTVisitor<PrintVisited> {
public: // methods
bool shouldVisitImplicitCode() const
{ return true; }
bool VisitStmt(clang::Stmt *stmt)
{
llvm::outs() << "VisitStmt: " << stmt->getStmtClassName()
<< " at " << stmt << "\n";
return true;
}
};
```
I get as output:
```
AST dump:
TranslationUnitDecl 0x5630d820e998 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x5630d820f200 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x5630d820ef60 '__int128'
|-TypedefDecl 0x5630d820f270 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x5630d820ef80 'unsigned __int128'
|-TypedefDecl 0x5630d820f5e8 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
| `-RecordType 0x5630d820f360 '__NSConstantString_tag'
| `-CXXRecord 0x5630d820f2c8 '__NSConstantString_tag'
|-TypedefDecl 0x5630d820f680 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x5630d820f640 'char *'
| `-BuiltinType 0x5630d820ea40 'char'
|-TypedefDecl 0x5630d8255658 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag[1]'
| `-ConstantArrayType 0x5630d8255600 '__va_list_tag[1]' 1
| `-RecordType 0x5630d820f770 '__va_list_tag'
| `-CXXRecord 0x5630d820f6d8 '__va_list_tag'
|-FunctionDecl 0x5630d8255700 <test.cc:4:1, col:13> col:5 used makeInt 'int ()'
|-FunctionDecl 0x5630d8255998 <line:6:1, col:26> col:6 used f1 'void (int)'
| `-ParmVarDecl 0x5630d8255808 <col:9, col:25> col:13 x 'int' cinit
| `-CallExpr 0x5630d8255920 <col:17, col:25> 'int'
| `-ImplicitCastExpr 0x5630d8255908 <col:17> 'int (*)()' <FunctionToPointerDecay>
| `-DeclRefExpr 0x5630d82558b8 <col:17> 'int ()' lvalue Function 0x5630d8255700 'makeInt' 'int ()'
`-FunctionDecl 0x5630d8255a98 <line:8:1, line:12:1> line:8:6 f2 'void ()'
`-CompoundStmt 0x5630d8255d00 <line:9:1, line:12:1>
|-CallExpr 0x5630d8255bf0 <line:10:3, col:6> 'void'
| |-ImplicitCastExpr 0x5630d8255bd8 <col:3> 'void (*)(int)' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x5630d8255b88 <col:3> 'void (int)' lvalue Function 0x5630d8255998 'f1' 'void (int)'
| `-CXXDefaultArgExpr 0x5630d8255c18 <<invalid sloc>> 'int'
`-CallExpr 0x5630d8255cb8 <line:11:3, col:6> 'void'
|-ImplicitCastExpr 0x5630d8255ca0 <col:3> 'void (*)(int)' <FunctionToPointerDecay>
| `-DeclRefExpr 0x5630d8255c80 <col:3> 'void (int)' lvalue Function 0x5630d8255998 'f1' 'void (int)'
`-CXXDefaultArgExpr 0x5630d8255ce0 <<invalid sloc>> 'int'
RAV visited Stmts:
VisitStmt: CallExpr at 0x5630d8255920 }
VisitStmt: ImplicitCastExpr at 0x5630d8255908 } 1
VisitStmt: DeclRefExpr at 0x5630d82558b8 }
VisitStmt: CompoundStmt at 0x5630d8255d00
VisitStmt: CallExpr at 0x5630d8255bf0
VisitStmt: ImplicitCastExpr at 0x5630d8255bd8
VisitStmt: DeclRefExpr at 0x5630d8255b88
VisitStmt: CXXDefaultArgExpr at 0x5630d8255c18
VisitStmt: CallExpr at 0x5630d8255920 }
VisitStmt: ImplicitCastExpr at 0x5630d8255908 } 2
VisitStmt: DeclRefExpr at 0x5630d82558b8 }
VisitStmt: CallExpr at 0x5630d8255cb8
VisitStmt: ImplicitCastExpr at 0x5630d8255ca0
VisitStmt: DeclRefExpr at 0x5630d8255c80
VisitStmt: CXXDefaultArgExpr at 0x5630d8255ce0
VisitStmt: CallExpr at 0x5630d8255920 }
VisitStmt: ImplicitCastExpr at 0x5630d8255908 } 3
VisitStmt: DeclRefExpr at 0x5630d82558b8 }
```
This fragment of output appears three times:
```
VisitStmt: CallExpr at 0x5630d8255920
VisitStmt: ImplicitCastExpr at 0x5630d8255908
VisitStmt: DeclRefExpr at 0x5630d82558b8
```
As I understand it, the reason is simply inherent to how `CXXDefaultArgExpr` works, as it just has a pointer to the `ParmVarDecl` that declares the default argument, and RAV follows that pointer if `shouldVisitImplicitCode()`:
```c++
// clang/AST/RecursiveASTVisitor.h
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, {
if (getDerived().shouldVisitImplicitCode())
TRY_TO(TraverseStmt(S->getExpr()));
})
```
As I don't see a simple way to make the behavior conform to (my understanding of) the documentation, I suggest changing the documentation to clarify that multiple visitation is possible in some cases. Ideally it would say what those cases are, but getting an exhaustive list may be difficult. I'm aware of this case, and also one noted in passing at the end of Issue #64820.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0Wc1S6zoSfhqz6YKyZeI4CxYhQA2LuXMLMtSZVUq227HusSWXJBPy9lMtOYnzC5x7LkVBYqu__vu6Lbe4MWIpEe-C0X0werjina2UvjNN3iL_eZWpYn03rxAKlXcNSsutUBJKpYEEkvAF804b8Y7T1_mbMMIqHSRhMHoIWFpZ25ogngbsKWBPec3l8qau35sbpZcBeyrUx3qJ0t8yxt1fRIvoBORNZZs6YHGBlovaBGwCAUtfpm_0yfC10xI-BOHmb_wI92sosORdbQM2A1sJA-8eDawWaMAqfwHwHfUaWq4tqBJshYAfbS1yYcGoTucIuSroIs9tvQYlc7wZaqP4NMilkEsPIAwYyy1SwEAYkMoCSis01mvIa-SalDdITgSMZQNLWRA_AQSMbWzsLwWMbYzyVwI2Ib-yzsIz4bSoK94aMKJpa2GsyHldryk-QlrUrUYLwgI3QAvWZKutuIWX6RuYSnV14cz0EeFyDdPXOUjyu1Eaaa089vxfakXBI0NECUESeiSXtefGmztTBTo_J0ESgkbbaWlordUdEldI2MJK1DUUCv7qjPWWEckoGTk3SHHtYwRcLx0VKUsajRFKGgJZVSKvCMr5YJy1W5AC85prz16HjsbyrBamoii7BfvohMhlAXzJhSc88ryCzrisdQYNcI2AMuet6WpusQAhHZSvjNmPHw8ec6qXjx_t366LI8C-KiYuTQGb7KXmiSz-4E1bowuOsJVnppBtZw_rJQn9bx6we_p1V4W00PCf-EzRcAmM74dS70oUUEYBS2nlBwTxw8H6MyKsv-1vjPsVHmooA8eXgvHDgclD-OcSnmGlhUXgUIvMKlUT01utlpo3Pa-ENhZcBilbFj-sI3vRNa3nsq1Qgu6kAQ5ne5wHa7WQ1gPxoiA6ElV9R3E8xIIgXm1jScZl6iuxd6mHPwn9bQMTT6Htslrk4DhBOPH0lHHxbChIzXAbZA9AUO7HUxAatJUqzCbqmVI1XCxlyJU0drMeCL8vbXBlHd_DLlNDVIfnosHSgRd0BQI2Ne7OZCOy4wYAUIn41aqzprcjiGdBPKP2uEOOp_R9c4sgr4P4cYnu7owC-wdvcMhBOPzZwQK3h2iDu8FoJl0_Hti5H4edKw87Bm_ZfJLEsETXqFVnL5Sq_7oh7nbVXHNpatfo_iuFfcC8hvBjlMRhkbIQJ5O0N1_Id16LAkyt8iB-dCw5vtqbPLuer1sssDzAK1kYfgfPPXzck3WxENJGLF1QeMebbwEbb1VS3Vzfd6K2QpL2oRtlEp4TO2vp-Jct7YamdtLtmAr4ts1p-Kn8OeNH-K20DY3_43VGtcqlfbWamqGL2-HVheXLI0deMFe6OPCjjDex_xQDHMrsxw8PtJeNPP0ayLmIJOkvpzPz-Vk0ZvHOF7RZIlPyimtqQUdR-FO5HdRhGJLb8KwYXOIB3wl-7uholIx-OfUbRwdeLjZfXJxH95Hbkhx4vMnIVGu-3jd_NErC8AIQRHAYhtMsGo9PwOzH8AJ9kiK9KH391MmceuBhNMe-X1k09ian5-BtEE8jeujnqqaPMcXQfx7RJqHYbGlIn3D__NbmC8r6ZlsLSQ_9ZF8TS3aaEq-pjEiJ2yP5TdWBIk9Hrps3rg91paHT5fEmAzWjnZoopl2ac4NSlQsp7FG18rqmzeWeHyzcYUfjQ_At4nHytjsHbuwR6tDiaLxD8iGeOuf7WNPCTZTnqq_IB8z5eviQ2jy8k_CawvOC5aHONLuo06mq33ndIWzUHbGHjbeb3PE5UiThWVLwPVKkG1L03yPmLsSPMFiQQMmGzBiq6gu2aVUnC7eNGugqPNt7qMk5XcN93OwkA7JyCBSFQTyNdzRI-jiSfTvDPJyDvESDrBikJB4g7dFgWwxfYMJA8yUuZOkFxTt9F-jg6puN6SVlfKFyt_b4brb_EjfEy6NLrX6_yuBCvebZkGJR9MVswae5ynn4D-QKPstUnl5Q-1sz9XmK8NK246ARur8v07ftmyDV525WtffGss0jt4etd__NZPMesSd9lLQDlDDdSkN0Qn4Y-H1R6pifad9rP_ywA33d2aw8tfgT37Ii_ZZDWXpq_XHS96Xy6KTU-aT9_Tyx35-n0-bm2SnfPjE156dydd6-PD1JhM_Cjt-gz-8Je_w7wn7yxX5eCQOl5ks3vVRl_4IPvG2RawO20ohgRYNH8-x9uC8G45cC8V3vL_g7NfAMnSxQ09tEAaKfxCNo5EZJEP24eg1CVqgpKlZBpVZwZn4KK6V_umEvNyCsHxZX3ACH1j9dCMDNYJNwsFHejuv8GPiTkS917FLVtVqZfsjXY39txv2l-V4_ePMjMPY0fZ0H7OnkyYdf__D4tJi_TN8eX14fF6_zf88Dlh5HiM0GIzOylqVLtA-oxTsW3sCby-ZvJ2Lzl_8t5v8JWDrX_B21wX5o99rP0ry-jczBhHY72z1Li0LJgI0tGETgngUIK752ByP8J7oEZVjxd6E05EqWSjd0M2Bpsx6wyh-6BGziUzo8pqJwPIPplks0FvKKy6U_9jg8zrKKEqFFufb5brraCjLIPbf9GmGgVcaIrEYQEoxq_MmEuQF4LpDXxGILK3eSYvgaVoRkK2X6dcA1bk5slmgtmcIl4EfFO2PFO4J7R2_4GjKEQpSlyLvaEjy9cgBfcY3b8yWC3B5R1EaBkghS9acQLTfG4Vt_nCULEnw2pkMIWJzcpizsTwuuiru4mMQTfoV3UTJJRqNRGIVX1R2OJpMsi8dpOCmzhN-O8yhlEx6Wt3kZphhfiTsWsjgKwySMomQU3rAknSCO81GYhTwbZ8FtiA0X9fZw40qQBXdJGo_Dq5pnWBt37siYxBW4m26m-nCl70jmOuuWJrgNKTBmh2KFrfHuRLEMDgX7M6BLZ0a7NLuWS_VysTauOl3f7Z_dLIWtuuwmV03Antx82v-7brX6C3MbsCfnlQnYk_P6_wEAAP__2D_EzA">