Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -234,9 +234,12 @@ } /// Returns whether we should create a global variable for the - /// given VarDecl. - bool shouldBeGloballyIndexed(const VarDecl *VD) const { - return VD->hasGlobalStorage() || VD->isConstexpr(); + /// given ValueDecl. + bool shouldBeGloballyIndexed(const ValueDecl *VD) const { + if (const auto *V = dyn_cast(VD)) + return V->hasGlobalStorage() || V->isConstexpr(); + + return false; } llvm::RoundingMode getRoundingMode(const Expr *E) const { Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -28,7 +28,7 @@ /// Scope used to handle temporaries in toplevel variable declarations. template class DeclScope final : public LocalScope { public: - DeclScope(ByteCodeExprGen *Ctx, const VarDecl *VD) + DeclScope(ByteCodeExprGen *Ctx, const ValueDecl *VD) : LocalScope(Ctx), Scope(Ctx->P, VD) {} void addExtended(const Scope::Local &Local) override { @@ -895,11 +895,11 @@ if (std::optional T = classify(LV->getType())) { if (!LV->refersToBitField()) { // Only primitive, non bit-field types can be dereferenced directly. - if (auto *DE = dyn_cast(LV)) { + if (const auto *DE = dyn_cast(LV)) { if (!DE->getDecl()->getType()->isReferenceType()) { - if (auto *PD = dyn_cast(DE->getDecl())) + if (const auto *PD = dyn_cast(DE->getDecl())) return dereferenceParam(LV, *T, PD, AK, Direct, Indirect); - if (auto *VD = dyn_cast(DE->getDecl())) + if (const auto *VD = dyn_cast(DE->getDecl())) return dereferenceVar(LV, *T, VD, AK, Direct, Indirect); } } @@ -1782,6 +1782,8 @@ } } else if (const auto *ECD = dyn_cast(Decl)) { return this->emitConst(ECD->getInitVal(), E); + } else if (const auto *BD = dyn_cast(Decl)) { + return this->visit(BD->getBinding()); } return false; Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -205,17 +205,11 @@ template bool ByteCodeStmtGen::visitDeclStmt(const DeclStmt *DS) { for (auto *D : DS->decls()) { - // Variable declarator. - if (auto *VD = dyn_cast(D)) { - if (!this->visitVarDecl(VD)) - return false; - continue; - } - - // Decomposition declarator. - if (auto *DD = dyn_cast(D)) { - return this->bail(DD); - } + const auto *VD = dyn_cast(D); + if (!VD) + return false; + if (!this->visitVarDecl(VD)) + return false; } return true; Index: clang/lib/AST/Interp/Program.h =================================================================== --- clang/lib/AST/Interp/Program.h +++ clang/lib/AST/Interp/Program.h @@ -131,7 +131,9 @@ /// Context to manage declaration lifetimes. class DeclScope { public: - DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); } + DeclScope(Program &P, const ValueDecl *VD) : P(P) { + P.startDeclaration(VD); + } ~DeclScope() { P.endDeclaration(); } private: @@ -222,7 +224,7 @@ unsigned CurrentDeclaration = NoDeclaration; /// Starts evaluating a declaration. - void startDeclaration(const VarDecl *Decl) { + void startDeclaration(const ValueDecl *Decl) { LastDeclaration += 1; CurrentDeclaration = LastDeclaration; } Index: clang/test/AST/Interp/cxx17.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/cxx17.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s +// RUN: %clang_cc1 -std=c++17 -verify=ref %s + +// ref-no-diagnostics + +struct F { int a; int b;}; +constexpr F getF() { + return {12, 3}; +} +constexpr int f() { + auto [a1, b1] = getF(); + auto [a2, b2] = getF(); + + return a1 + a2 + b1 + b2; +} +static_assert(f() == 30); + + +constexpr int structRefs() { + const auto &[a, b] = getF(); + + return a + b; +} +// FIXME: This should work, but the MaterializeTemporaryExpr handling is not ready for it. +static_assert(structRefs() == 15); // expected-error {{not an integral constant expression}} + +constexpr int structRefs2() { + F f = getF(); + const auto &[a, b] = f; + + return a + b; +} +static_assert(structRefs2() == 15); + + +template +struct Tuple { + T first; + T second; + constexpr Tuple(T a, T b) : first(a), second(b) {} +}; +template +constexpr T addTuple(const Tuple &Tu) { + auto [a, b] = Tu; + return a + b; +} + +template +constexpr T addTuple2(const Tuple &Tu) { + auto [a, b] = Tu; + return Tu.first + Tu.second; +} + +constexpr Tuple T1 = Tuple(1,2); +static_assert(addTuple(T1) == 3); +static_assert(addTuple2(T1) == 3); + +constexpr Tuple T2 = Tuple(11,2); +static_assert(addTuple(T2) == 13); +static_assert(addTuple2(T2) == 13); + +constexpr int Modify() { + auto T = Tuple(10, 20); + auto &[x, y] = T; + x += 1; + y += 1; + return T.first + T.second; +} +static_assert(Modify() == 32, ""); + +constexpr int a() { + int a[2] = {5, 3}; + auto [x, y] = a; + return x + y; +} +static_assert(a() == 8); + +constexpr int b() { + int a[2] = {5, 3}; + auto &[x, y] = a; + x += 1; + y += 2; + return a[0] + a[1]; +} +static_assert(b() == 11);