diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8200,9 +8200,21 @@ if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); + QualType MTETy = Step->Type; + + // When this is an incomplete array type (such as when this is + // initializing an array of unknown bounds from an init list), use THAT + // type instead so that we propogate the array bounds. + if (MTETy->isIncompleteArrayType() && + !CurInit.get()->getType()->isIncompleteArrayType() && + S.Context.hasSameType( + MTETy->getPointeeOrArrayElementType(), + CurInit.get()->getType()->getPointeeOrArrayElementType())) + MTETy = CurInit.get()->getType(); + // Materialize the temporary into memory. MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr( - Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType()); + MTETy, CurInit.get(), Entity.getType()->isLValueReferenceType()); CurInit = MTE; // If we're extending this temporary to automatic storage duration -- we diff --git a/clang/test/AST/pr47636.cpp b/clang/test/AST/pr47636.cpp new file mode 100644 --- /dev/null +++ b/clang/test/AST/pr47636.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only %s -ast-dump | FileCheck %s + +int(&&intu_rvref)[] {1,2,3,4}; +// CHECK: VarDecl 0x[[GLOB_ADDR:[0-9a-f]+]] {{.*}} intu_rvref 'int (&&)[4]' listinit +// CHECK-NEXT: ExprWithCleanups {{.*}} 'int [4]' xvalue +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int [4]' xvalue extended by Var 0x[[GLOB_ADDR]] 'intu_rvref' 'int (&&)[4]' +// CHECK-NEXT: InitListExpr {{.*}} 'int [4]' + +// CHECK: FunctionDecl {{.*}} static_const +void static_const() { + static const int(&&intu_rvref)[] {1,2,3,4}; + // CHECK: VarDecl 0x[[STATIC_ADDR:[0-9a-f]+]] {{.*}} intu_rvref 'const int (&&)[4]' static listinit + // CHECK-NEXT: ExprWithCleanups {{.*}} 'const int [4]' xvalue + // CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const int [4]' xvalue extended by Var 0x[[STATIC_ADDR]] 'intu_rvref' 'const int (&&)[4]' + // CHECK-NEXT: InitListExpr {{.*}} 'const int [4]' +} + +// CHECK: FunctionDecl {{.*}} const_expr +constexpr int const_expr() { + int(&&intu_rvref)[]{1, 2, 3, 4}; + // CHECK: VarDecl 0x[[CE_ADDR:[0-9a-f]+]] {{.*}} intu_rvref 'int (&&)[4]' listinit + // CHECK-NEXT: ExprWithCleanups {{.*}} 'int [4]' xvalue + // CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int [4]' xvalue extended by Var 0x[[CE_ADDR]] 'intu_rvref' 'int (&&)[4]' + // CHECK-NEXT: InitListExpr {{.*}} 'int [4]' + return intu_rvref[0]; +} diff --git a/clang/test/CodeGenCXX/pr47636.cpp b/clang/test/CodeGenCXX/pr47636.cpp --- a/clang/test/CodeGenCXX/pr47636.cpp +++ b/clang/test/CodeGenCXX/pr47636.cpp @@ -8,3 +8,15 @@ // CHECK: @_ZZ3foovE10intu_rvref = internal constant [4 x i32]* @_ZGRZ3foovE10intu_rvref_ // CHECK: @_ZGRZ3foovE10intu_rvref_ = internal constant [4 x i32] [i32 1, i32 2, i32 3, i32 4] } + +// Example given on review, ensure this doesn't crash as well. +constexpr int f() { + // CHECK: i32 @_Z1fv() + int(&&intu_rvref)[]{1, 2, 3, 4}; + // CHECK: %{{.*}} = alloca [4 x i32]* + return intu_rvref[2]; +} + +void use_f() { + int i = f(); +}