aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Pilkington2017-10-03 19:18:55 -0500
committerErik Pilkington2017-10-03 19:18:55 -0500
commit15b35a3943d2743eea7908bf3eede18cbee4d7b0 (patch)
treedd36e06b4ae9236cc5e8938ee6b58641b4ec8f43
parenta171bb0ee4a63cd1e6bdffc81a71bca914a929a9 (diff)
downloadclang-15b35a3943d2743eea7908bf3eede18cbee4d7b0.tar.gz
clang-15b35a3943d2743eea7908bf3eede18cbee4d7b0.tar.xz
clang-15b35a3943d2743eea7908bf3eede18cbee4d7b0.zip
[ExprConstant] Allow constexpr ctor to modify non static data members
Fixes PR19741. Differential revision: https://reviews.llvm.org/D38483 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314865 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/ExprConstant.cpp33
-rw-r--r--test/SemaCXX/constant-expression-cxx1y.cpp33
2 files changed, 63 insertions, 3 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index be4b3af4d6..28f0446117 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -573,6 +573,31 @@ namespace {
573 /// declaration whose initializer is being evaluated, if any. 573 /// declaration whose initializer is being evaluated, if any.
574 APValue *EvaluatingDeclValue; 574 APValue *EvaluatingDeclValue;
575 575
576 /// EvaluatingObject - Pair of the AST node that an lvalue represents and
577 /// the call index that that lvalue was allocated in.
578 typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject;
579
580 /// EvaluatingConstructors - Set of objects that are currently being
581 /// constructed.
582 llvm::DenseSet<EvaluatingObject> EvaluatingConstructors;
583
584 struct EvaluatingConstructorRAII {
585 EvalInfo &EI;
586 EvaluatingObject Object;
587 bool DidInsert;
588 EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object)
589 : EI(EI), Object(Object) {
590 DidInsert = EI.EvaluatingConstructors.insert(Object).second;
591 }
592 ~EvaluatingConstructorRAII() {
593 if (DidInsert) EI.EvaluatingConstructors.erase(Object);
594 }
595 };
596
597 bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) {
598 return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex));
599 }
600
576 /// The current array initialization index, if we're performing array 601 /// The current array initialization index, if we're performing array
577 /// initialization. 602 /// initialization.
578 uint64_t ArrayInitIndex = -1; 603 uint64_t ArrayInitIndex = -1;
@@ -666,6 +691,7 @@ namespace {
666 void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { 691 void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
667 EvaluatingDecl = Base; 692 EvaluatingDecl = Base;
668 EvaluatingDeclValue = &Value; 693 EvaluatingDeclValue = &Value;
694 EvaluatingConstructors.insert({Base, 0});
669 } 695 }
670 696
671 const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } 697 const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
@@ -3098,10 +3124,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
3098 } 3124 }
3099 3125
3100 // During the construction of an object, it is not yet 'const'. 3126 // During the construction of an object, it is not yet 'const'.
3101 // FIXME: We don't set up EvaluatingDecl for local variables or temporaries, 3127 // FIXME: This doesn't do quite the right thing for const subobjects of the
3102 // and this doesn't do quite the right thing for const subobjects of the
3103 // object under construction. 3128 // object under construction.
3104 if (LVal.getLValueBase() == Info.EvaluatingDecl) { 3129 if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) {
3105 BaseType = Info.Ctx.getCanonicalType(BaseType); 3130 BaseType = Info.Ctx.getCanonicalType(BaseType);
3106 BaseType.removeLocalConst(); 3131 BaseType.removeLocalConst();
3107 } 3132 }
@@ -4254,6 +4279,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
4254 return false; 4279 return false;
4255 } 4280 }
4256 4281
4282 EvalInfo::EvaluatingConstructorRAII EvalObj(
4283 Info, {This.getLValueBase(), This.CallIndex});
4257 CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); 4284 CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
4258 4285
4259 // FIXME: Creating an APValue just to hold a nonexistent return value is 4286 // FIXME: Creating an APValue just to hold a nonexistent return value is
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index 0c0cb0ec58..12fec08516 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -988,3 +988,36 @@ constexpr void Void(int n) {
988 void(); 988 void();
989} 989}
990constexpr int void_test = (Void(0), 1); 990constexpr int void_test = (Void(0), 1);
991
992namespace PR19741 {
993constexpr void addone(int &m) { m++; }
994
995struct S {
996 int m = 0;
997 constexpr S() { addone(m); }
998};
999constexpr bool evalS() {
1000 constexpr S s;
1001 return s.m == 1;
1002}
1003static_assert(evalS(), "");
1004
1005struct Nested {
1006 struct First { int x = 42; };
1007 union {
1008 First first;
1009 int second;
1010 };
1011 int x;
1012 constexpr Nested(int x) : first(), x(x) { x = 4; }
1013 constexpr Nested() : Nested(42) {
1014 addone(first.x);
1015 x = 3;
1016 }
1017};
1018constexpr bool evalNested() {
1019 constexpr Nested N;
1020 return N.first.x == 43;
1021}
1022static_assert(evalNested(), "");
1023} // namespace PR19741