aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/TreeTransform.h6
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp13
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>();
+}