llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
26.82k stars 11k forks source link

Unexpected AST for consteval constructor call #57383

Open Abramo-Bagnara opened 1 year ago

Abramo-Bagnara commented 1 year ago

The presence of CXXFunctionalCastExpr is triggered by consteval, but I don't see any reason for that.

Note also how -ast-print is confused by that.

abramo@igor:/tmp$ cat p.cc
struct A {
  consteval A () {}
};

void f() {
  A{};
}
abramo@igor:/tmp$ clang++-16 -cc1 -std=c++20 -ast-print p.cc
p.cc:6:3: warning: expression result unused [-Wunused-value]
  A{};
  ^~~
struct A {
    consteval A() {
    }
};
void f() {
    AA{};
}
1 warning generated.
abramo@igor:/tmp$ clang++-16 -cc1 -std=c++20 -ast-dump p.cc
p.cc:6:3: warning: expression result unused [-Wunused-value]
  A{};
  ^~~
TranslationUnitDecl 0x55768bf3ce98 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x55768bf3d720 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x55768bf3d460 '__int128'
|-TypedefDecl 0x55768bf3d798 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x55768bf3d480 'unsigned __int128'
|-TypedefDecl 0x55768bf3db50 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
| `-RecordType 0x55768bf3d8a0 '__NSConstantString_tag'
|   `-CXXRecord 0x55768bf3d7f8 '__NSConstantString_tag'
|-TypedefDecl 0x55768bf3dbf8 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x55768bf3dbb0 'char *'
|   `-BuiltinType 0x55768bf3cf40 'char'
|-TypedefDecl 0x55768bf88910 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag[1]'
| `-ConstantArrayType 0x55768bf888b0 '__va_list_tag[1]' 1 
|   `-RecordType 0x55768bf3dd00 '__va_list_tag'
|     `-CXXRecord 0x55768bf3dc58 '__va_list_tag'
|-CXXRecordDecl 0x55768bf88970 <p.cc:1:1, line:3:1> line:1:8 referenced struct A definition
| |-DefinitionData pass_in_registers empty standard_layout trivially_copyable literal has_user_declared_ctor has_constexpr_non_copy_move_ctor can_const_default_init
| | |-DefaultConstructor exists non_trivial user_provided constexpr defaulted_is_constexpr
| | |-CopyConstructor simple trivial has_const_param implicit_has_const_param
| | |-MoveConstructor exists simple trivial
| | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveAssignment exists simple trivial needs_implicit
| | `-Destructor simple irrelevant trivial constexpr
| |-CXXRecordDecl 0x55768bf88ab0 <col:1, col:8> col:8 implicit referenced struct A
| |-CXXConstructorDecl 0x55768bf88bf0 <line:2:3, col:19> col:13 used consteval A 'void ()' implicit-inline
| | `-CompoundStmt 0x55768bf88cc8 <col:18, col:19>
| |-CXXConstructorDecl 0x55768bf88f80 <line:1:8> col:8 implicit constexpr A 'void (const A &)' inline default trivial noexcept-unevaluated 0x55768bf88f80
| | `-ParmVarDecl 0x55768bf890a0 <col:8> col:8 'const A &'
| |-CXXConstructorDecl 0x55768bf89150 <col:8> col:8 implicit constexpr A 'void (A &&)' inline default trivial noexcept-unevaluated 0x55768bf89150
| | `-ParmVarDecl 0x55768bf89270 <col:8> col:8 'A &&'
| `-CXXDestructorDecl 0x55768bf893b0 <col:8> col:8 implicit referenced constexpr ~A 'void () noexcept' inline default trivial
`-FunctionDecl 0x55768bf88dc0 <line:5:1, line:7:1> line:5:6 f 'void ()'
  `-CompoundStmt 0x55768bf89500 <col:10, line:7:1>
    `-CXXFunctionalCastExpr 0x55768bf894d8 <line:6:3, col:5> 'A':'A' functional cast to A <NoOp>
      `-ConstantExpr 0x55768bf89348 <col:3, col:5> 'A':'A'
        |-value: Struct
        `-CXXTemporaryObjectExpr 0x55768bf89318 <col:3, col:5> 'A':'A' 'void ()' list
1 warning generated.
llvmbot commented 1 year ago

@llvm/issue-subscribers-clang-frontend

AaronBallman commented 1 year ago

I don't think this is entirely unexpected, though the -ast-print behavior is a bug. CXXTemporaryObjectExpr has the following comments:

/// Represents a C++ functional cast expression that builds a
/// temporary object.

so it's not too surprising that you get a temp object AST node in some cases and a functional cast in others. In this case, I believe what's happening is that use of a type with a consteval constructor results in a functional cast because no temporary object is created in that case. You get the same behavior with int{} as you do with A{}, for example.