diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d90a2b53eb616..8d0a9c96a9579 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -386,6 +386,7 @@ Bug Fixes to C++ Support - Fix overly aggressive lifetime checks for parenthesized aggregate initialization. (`#61567 `_) +- Fix a crash when expanding a pack as the index of a subscript expression. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4edaf6970a2d7..8789e4c3cb25f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4924,7 +4924,8 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, // Build an unanalyzed expression if either operand is type-dependent. if (getLangOpts().CPlusPlus && ArgExprs.size() == 1 && (base->isTypeDependent() || - Expr::hasAnyTypeDependentArguments(ArgExprs))) { + Expr::hasAnyTypeDependentArguments(ArgExprs)) && + !isa(ArgExprs[0])) { return new (Context) ArraySubscriptExpr( base, ArgExprs.front(), getDependentArraySubscriptType(base, ArgExprs.front(), getASTContext()), @@ -4958,7 +4959,8 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, // to overload resolution and so should not take this path. if (getLangOpts().CPlusPlus && !base->getType()->isObjCObjectPointerType() && ((base->getType()->isRecordType() || - (ArgExprs.size() != 1 || ArgExprs[0]->getType()->isRecordType())))) { + (ArgExprs.size() != 1 || isa(ArgExprs[0]) || + ArgExprs[0]->getType()->isRecordType())))) { return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, ArgExprs); } diff --git a/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp b/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp index f9a83c813dcf0..47218e1f2dab5 100644 --- a/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp +++ b/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp @@ -73,3 +73,47 @@ struct T2 { static_assert(T2{}[] == 1); static_assert(T2{}[1] == 2); static_assert(T2{}[1, 1] == 3); + +namespace test_packs { + +struct foo_t { +template +constexpr int operator[](Ts... idx) { + return (0 + ... + idx); +} +}; + +template +constexpr int cxx_subscript() { + foo_t foo; + return foo[Is...]; +} + +template +int cxx_subscript_unexpanded() { + foo_t foo; + return foo[Is]; // expected-error {{expression contains unexpanded parameter pack 'Is'}} +} + +template +constexpr int c_array() { + int arr[] = {1, 2, 3}; + return arr[Is...]; // expected-error 2{{type 'int[3]' does not provide a subscript operator}} +} + +template +int c_array_unexpanded() { + int arr[] = {1, 2, 3}; + return arr[Is]; // expected-error {{expression contains unexpanded parameter pack 'Is'}} +} + +void test() { + static_assert(cxx_subscript<1, 2, 3>() == 6); + static_assert(c_array<1>() == 2); + + c_array<>(); // expected-note {{in instantiation}} + c_array<1>(); + c_array<1, 2>(); // expected-note {{in instantiation}} +} + +}