Skip to content

discrepancy between clang and gcc regarding list initialization #72396

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

Closed
yxsamliu opened this issue Nov 15, 2023 · 7 comments
Closed

discrepancy between clang and gcc regarding list initialization #72396

yxsamliu opened this issue Nov 15, 2023 · 7 comments
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. duplicate Resolved as duplicate

Comments

@yxsamliu
Copy link
Collaborator

yxsamliu commented Nov 15, 2023

There is a discrepancy between clang and gcc regarding list initialization when there is only one element in the list:

#include <stdio.h>
#include <initializer_list>
#include <utility>
 
class list {
public:
  list() {
    printf("default ctor\n");
  }
 
  list(std::initializer_list<list> elem ) {
    printf("list ctor\n");
  }
};
 
int main(int argc, char **argv) {
 
  list mylist{list{}};
}

In the above code, clang does not use the list ctor but gcc uses.

https://godbolt.org/z/17WaacKG3

https://godbolt.org/z/5nbEP14qv

Open this ticket to discuss which behavior is correct.

@zygoloid

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Nov 15, 2023
@EugeneZelenko EugeneZelenko added clang:codegen IR generation bugs: mangling, exceptions, etc. and removed clang Clang issues not falling into any other category labels Nov 15, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 15, 2023

@llvm/issue-subscribers-clang-codegen

Author: Yaxun (Sam) Liu (yxsamliu)

There is a discrepancy between clang and gcc regarding list initialization when there is only one element in the list:

`#include <stdio.h>
#include <initializer_list>
#include <utility>

class list {
public:
list() {
printf("default ctor\n");
}

list(std::initializer_list<list> elem ) {
printf("list ctor\n");
}
};

int main(int argc, char **argv) {

list mylist{list{}};
}`

In the above code, clang does not use the list ctor but gcc uses.

https://godbolt.org/z/17WaacKG3

https://godbolt.org/z/5nbEP14qv

Open this ticket to discuss which behavior is correct.

@zygoloid

@yxsamliu
Copy link
Collaborator Author

According to https://en.cppreference.com/w/cpp/language/list_initialization

If T is an aggregate class and the braced-init-list, which does not contain a designated initializer list,(since C++20) has a single element of the same or derived type (possibly cv-qualified), the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

However, there is some ambiguity about whether this should be applied to the case here. The key point is what "an aggregate class" means here. Is any class "aggregate class" so that this term applies, or "an aggregate class" has to be some specific form of class, e.g. array of class. In the latter case, then this term does not apply.

@yxsamliu
Copy link
Collaborator Author

msvc behaves the same as clang https://godbolt.org/z/zh3xMcnnb

@shafik
Copy link
Collaborator

shafik commented Nov 18, 2023

It looks like we might be doing copy elision here but I believe we should not be.

CC @zygoloid @hubert-reinterpretcast

@domcharrier
Copy link

domcharrier commented Nov 20, 2023

clang -Xclang -ast-dump -fsyntax-only test.cpp | grep "main" -A 10000

`-FunctionDecl 0x564d8add4be0 <line:16:1, line:18:1> line:16:5 main 'int (int, char **)'
  |-ParmVarDecl 0x564d8add4a80 <col:10, col:14> col:14 argc 'int'
  |-ParmVarDecl 0x564d8add4b00 <col:20, col:27> col:27 argv 'char **'
  `-CompoundStmt 0x564d8add53d8 <col:33, line:18:1>
    `-DeclStmt 0x564d8add53c0 <line:17:3, col:22>
      `-VarDecl 0x564d8add4ca8 <col:3, col:21> col:8 mylist 'list':'list' listinit
        `-InitListExpr 0x564d8add5378 <col:14, col:21> 'list':'list'
          `-CXXTemporaryObjectExpr 0x564d8add5218 <col:15, col:20> 'list':'list' 'void ()' list

Input test.cpp:

#include <stdio.h>
#include <initializer_list>
#include <utility>

class list {
public:
  list() {
    printf("default ctor\\n");
  }

  list(std::initializer_list<list> elem ) {
    printf("list ctor\n");
  }
};
 
int main(int argc, char **argv) {
  list mylist{list{}};
}

@yxsamliu
Copy link
Collaborator Author

yxsamliu commented Jan 9, 2024

It looks like we might be doing copy elision here but I believe we should not be.

CC @zygoloid @hubert-reinterpretcast

Agree. It seems "aggregate class" cannot have user-defined constructors (https://en.cppreference.com/w/cpp/language/aggregate_initialization). Therefore in this case the constructor list(std::initializer_list<list> elem ) should be used. gcc's behavior seems to be correct.

@zygoloid
Copy link
Collaborator

zygoloid commented Jan 9, 2024

The discussion of aggregates here is a red herring.

The Clang behavior was required by CWG1467, but it caused #24186, so I filed CWG2137 to reverse that change. Clang has implemented CWG1467 but not yet implemented CWG2137.

Closing as duplicate of #24186.

@zygoloid zygoloid closed this as not planned Won't fix, can't repro, duplicate, stale Jan 9, 2024
@EugeneZelenko EugeneZelenko added the duplicate Resolved as duplicate label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. duplicate Resolved as duplicate
Projects
None yet
Development

No branches or pull requests

6 participants