diff options
-rw-r--r-- | lib/Sema/TreeTransform.h | 6 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 13 |
2 files changed, 18 insertions, 1 deletions
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 2d22e4ca64..52f647083a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -142,7 +142,11 @@ public: /// /// Subclasses may override this function to specify when the transformation /// should rebuild all AST nodes. - bool AlwaysRebuild() { return false; } + /// + /// We must always rebuild all AST nodes when performing variadic template + /// pack expansion, in order to avoid violating the AST invariant that each + /// statement node appears at most once in its containing declaration. + bool AlwaysRebuild() { return SemaRef.ArgumentPackSubstitutionIndex != -1; } /// \brief Returns the location of the entity being transformed, if that /// information was not available elsewhere in the AST. diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index c721d7e33c..664daf081b 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1811,3 +1811,16 @@ namespace NeverConstantTwoWays { 1 / 0 : // expected-warning {{division by zero}} expected-note {{division by zero}} 0; } + +namespace PR17800 { + struct A { + constexpr int operator()() const { return 0; } + }; + template <typename ...T> constexpr int sink(T ...) { + return 0; + } + template <int ...N> constexpr int run() { + return sink(A()() + N ...); + } + constexpr int k = run<1, 2, 3>(); +} |