aaronpuchert created this revision. aaronpuchert added a reviewer: rsmith. aaronpuchert requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
It was always just a placeholder, but not a particularly good one: the expression certainly has a value in most cases, and 'void' can also not serve as an indicator for an undeduced type because of void{}. Instead I think the dependent type is a good fit: an initializer list is an expression that can instantiate to expressions of arbitrary types: One could say that {...} is a map T : Type → T, T ↦ T{...} The type parameter can be explicitly specified or be deduced from an implicit conversion target type. So one could for example view {1} as struct InitList1 { template<typename T> operator T() { return T{1}; } }; That in itself isn't type-dependent, but note that we let InitListExprs have the actual type they initialize in the end, so in this case 'T' instead of 'InitList1'. A test failure in CXX/expr/expr.prim/expr.prim.lambda/p4.cpp revealed that we were emitting errors "return type ... must match previous return type ... when lambda expression has unspecified explicit return type" even after diagnosing InitListExprs with "cannot deduce lambda return type from initializer list", which in this case didn't show up because it accidentally matched with the actual 'void' of the other return statements. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D113837 Files: clang/include/clang/AST/Expr.h clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaInit.cpp clang/lib/Sema/SemaLambda.cpp clang/test/AST/ast-dump-decl.cpp clang/test/AST/ast-dump-recovery.cpp clang/test/AST/ast-dump-stmt-json.cpp clang/test/SemaOpenCLCXX/address-space-references.clcpp
Index: clang/test/SemaOpenCLCXX/address-space-references.clcpp =================================================================== --- clang/test/SemaOpenCLCXX/address-space-references.clcpp +++ clang/test/SemaOpenCLCXX/address-space-references.clcpp @@ -22,7 +22,7 @@ bar(1); // expected-error{{binding reference of type 'const __global unsigned int' to value of type 'int' changes address space}} C c; c.gen({1, 2}); - c.glob({1, 2}); //expected-error{{binding reference of type 'const __global short2' (vector of 2 'short' values) to value of type 'void' changes address space}} + c.glob({1, 2}); //expected-error{{binding reference of type 'const __global short2' (vector of 2 'short' values) to value of type '<dependent type>' changes address space}} c.nested_list({{1, 2}, {3, 4}}); } Index: clang/test/AST/ast-dump-stmt-json.cpp =================================================================== --- clang/test/AST/ast-dump-stmt-json.cpp +++ clang/test/AST/ast-dump-stmt-json.cpp @@ -2455,7 +2455,7 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "void" +// CHECK-NEXT: "qualType": "<dependent type>" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "prvalue" // CHECK-NEXT: } Index: clang/test/AST/ast-dump-recovery.cpp =================================================================== --- clang/test/AST/ast-dump-recovery.cpp +++ clang/test/AST/ast-dump-recovery.cpp @@ -197,7 +197,7 @@ Bar b3 = Bar(x); // CHECK: `-VarDecl {{.*}} b4 'Bar' // CHECK-NEXT: `-RecoveryExpr {{.*}} 'Bar' contains-errors - // CHECK-NEXT: `-InitListExpr {{.*}} 'void' + // CHECK-NEXT: `-InitListExpr {{.*}} '<dependent type>' // CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int' Bar b4 = Bar{x}; // CHECK: `-VarDecl {{.*}} b5 'Bar' Index: clang/test/AST/ast-dump-decl.cpp =================================================================== --- clang/test/AST/ast-dump-decl.cpp +++ clang/test/AST/ast-dump-decl.cpp @@ -607,7 +607,7 @@ // CHECK: VarTemplateDecl 0x{{.+}} parent 0x{{.+}} prev 0x{{.+}} <{{.+}}:[[@LINE-23]]:3, line:[[@LINE-22]]:34> col:14 TestVarTemplate // CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <line:[[@LINE-24]]:12, col:21> col:21 referenced typename depth 0 index 0 T // CHECK-NEXT: |-VarDecl 0x{{.+}} parent 0x{{.+}} prev 0x{{.+}} <line:[[@LINE-24]]:3, col:34> col:14 TestVarTemplate 'const T' cinit - // CHECK-NEXT: | `-InitListExpr 0x{{.+}} <col:32, col:34> 'void' + // CHECK-NEXT: | `-InitListExpr 0x{{.+}} <col:32, col:34> '<dependent type>' // CHECK-NEXT: |-VarTemplateSpecialization 0x{{.+}} 'TestVarTemplate' 'const int':'const int' // CHECK-NEXT: `-VarTemplateSpecialization 0x{{.+}} 'TestVarTemplate' 'const int':'const int' Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -780,6 +780,9 @@ continue; } + if (isa_and_nonnull<InitListExpr>(RetE)) + continue; // Should have been diagnosed already, type is bogus. + // FIXME: This is a poor diagnostic for ReturnStmts without expressions. // TODO: It's possible that the *first* return is the divergent one. Diag(RS->getBeginLoc(), Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -744,7 +744,7 @@ InitListExpr *OuterILE, unsigned OuterIndex, bool FillWithNoInit) { - assert((ILE->getType() != SemaRef.Context.VoidTy) && + assert((ILE->getType() != SemaRef.Context.DependentTy) && "Should not have void type"); // We don't need to do any checks when just filling NoInitExprs; that can't Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -886,8 +886,7 @@ // is ill-formed. // // Since we've already performed array-to-pointer and function-to-pointer - // decay, the only such type in C++ is cv void. This also handles - // initializer lists as variadic arguments. + // decay, the only such type in C++ is cv void. if (Ty->isVoidType()) return VAK_Invalid; @@ -896,6 +895,10 @@ return VAK_Valid; } + // This covers initializer lists. + if (Ty->isDependentType()) + return VAK_Invalid; + if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) return VAK_Invalid; @@ -7155,7 +7158,7 @@ InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList, RBraceLoc); - E->setType(Context.VoidTy); // FIXME: just a place holder for now. + E->setType(Context.DependentTy); return E; } Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -4749,8 +4749,8 @@ /// @endcode /// /// Prior to semantic analysis, an initializer list will represent the -/// initializer list as written by the user, but will have the -/// placeholder type "void". This initializer list is called the +/// initializer list as written by the user, but will have dependent +/// type as placeholder. This initializer list is called the /// syntactic form of the initializer, and may contain C99 designated /// initializers (represented as DesignatedInitExprs), initializations /// of subobject members without explicit braces, and so on. Clients
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits