<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Is AST incorrectly representing C++'s explicit casts?"
   href="https://bugs.llvm.org/show_bug.cgi?id=38017">38017</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Is AST incorrectly representing C++'s explicit casts?
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Frontend
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>lebedev.ri@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre><a href="https://godbolt.org/g/eE1GkJ">https://godbolt.org/g/eE1GkJ</a>

Given this simple C source, containing the explicit cast:

unsigned char t0(unsigned int src) {
  return (unsigned char)src;
}

The resulting AST is as you would expect:

TranslationUnitDecl
`-FunctionDecl <line:1:1, line:3:1> line:1:15 t0 'unsigned char (unsigned int)'
  |-ParmVarDecl <col:18, col:31> col:31 used src 'unsigned int'
  `-CompoundStmt <col:36, line:3:1>
    `-ReturnStmt <line:2:3, col:25>
      `-CStyleCastExpr <col:10, col:25> 'unsigned char' <IntegralCast>
        `-ImplicitCastExpr <col:25> 'unsigned int' <LValueToRValue>
          `-DeclRefExpr <col:25> 'unsigned int' lvalue ParmVar 0x563fcaa5ad70
'src' 'unsigned int'

The CStyleCastExpr is not an NoOp, it actually does what is spelled in the
source code.

But.

Given this C++ source code:

unsigned char t0(unsigned int src) {
  return (unsigned char)src;
}
unsigned char t1(unsigned int src) {
  return static_cast<unsigned char>(src);
}
using UnsignedChar = unsigned char;
UnsignedChar t2(unsigned int src) {
  return UnsignedChar(src);
}
unsigned char t3(unsigned int src) {
  return static_cast<UnsignedChar>(src);
}


The AST is strange:

TranslationUnitDecl
|-FunctionDecl <line:1:1, line:3:1> line:1:15 t0 'unsigned char (unsigned int)'
| |-ParmVarDecl <col:18, col:31> col:31 used src 'unsigned int'
| `-CompoundStmt <col:36, line:3:1>
|   `-ReturnStmt <line:2:3, col:25>
|     `-CStyleCastExpr <col:10, col:25> 'unsigned char' <NoOp>
|       `-ImplicitCastExpr <col:25> 'unsigned char' <IntegralCast>
|         `-ImplicitCastExpr <col:25> 'unsigned int' <LValueToRValue>
|           `-DeclRefExpr <col:25> 'unsigned int' lvalue ParmVar 0x55b2a6f4d720
'src' 'unsigned int'
|-FunctionDecl <line:4:1, line:6:1> line:4:15 t1 'unsigned char (unsigned int)'
| |-ParmVarDecl <col:18, col:31> col:31 used src 'unsigned int'
| `-CompoundStmt <col:36, line:6:1>
|   `-ReturnStmt <line:5:3, col:40>
|     `-CXXStaticCastExpr <col:10, col:40> 'unsigned char' static_cast<unsigned
char> <NoOp>
|       `-ImplicitCastExpr <col:37> 'unsigned char' <IntegralCast>
|         `-ImplicitCastExpr <col:37> 'unsigned int' <LValueToRValue>
|           `-DeclRefExpr <col:37> 'unsigned int' lvalue ParmVar 0x55b2a6f4d9b0
'src' 'unsigned int'
|-TypeAliasDecl <line:7:1, col:31> col:7 referenced UnsignedChar 'unsigned
char'
| `-BuiltinType 'unsigned char'
|-FunctionDecl <line:8:1, line:10:1> line:8:14 t2 'UnsignedChar (unsigned int)'
| |-ParmVarDecl <col:17, col:30> col:30 used src 'unsigned int'
| `-CompoundStmt <col:35, line:10:1>
|   `-ReturnStmt <line:9:3, col:26>
|     `-CXXFunctionalCastExpr <col:10, col:26> 'UnsignedChar':'unsigned char'
functional cast to UnsignedChar <NoOp>
|       `-ImplicitCastExpr <col:23> 'UnsignedChar':'unsigned char'
<IntegralCast>
|         `-ImplicitCastExpr <col:23> 'unsigned int' <LValueToRValue>
|           `-DeclRefExpr <col:23> 'unsigned int' lvalue ParmVar 0x55b2a6f4dc68
'src' 'unsigned int'
`-FunctionDecl <line:11:1, line:13:1> line:11:15 t3 'unsigned char (unsigned
int)'
  |-ParmVarDecl <col:18, col:31> col:31 used src 'unsigned int'
  `-CompoundStmt <col:36, line:13:1>
    `-ReturnStmt <line:12:3, col:39>
      `-CXXStaticCastExpr <col:10, col:39> 'UnsignedChar':'unsigned char'
static_cast<UnsignedChar> <NoOp>
        `-ImplicitCastExpr <col:36> 'UnsignedChar':'unsigned char'
<IntegralCast>
          `-ImplicitCastExpr <col:36> 'unsigned int' <LValueToRValue>
            `-DeclRefExpr <col:36> 'unsigned int' lvalue ParmVar 0x55b2a6f4deb0
'src' 'unsigned int'

So all the CStyleCastExpr/CXXStaticCastExpr/CXXFunctionalCastExpr are actually
NoOp,
and an ImplicitCastExpr is inserted as their child, which actually does the
cast.

Is this actually correct? It looks at the very least fishy to me.
Can this be fixed so these explicit casts are not a NoOp, but actually do the
work?

This complicates #21530.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>