diff options
author | Erik Pilkington | 2017-10-03 19:18:55 -0500 |
---|---|---|
committer | Erik Pilkington | 2017-10-03 19:18:55 -0500 |
commit | 15b35a3943d2743eea7908bf3eede18cbee4d7b0 (patch) | |
tree | dd36e06b4ae9236cc5e8938ee6b58641b4ec8f43 | |
parent | a171bb0ee4a63cd1e6bdffc81a71bca914a929a9 (diff) | |
download | clang-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.cpp | 33 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx1y.cpp | 33 |
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 | } |
990 | constexpr int void_test = (Void(0), 1); | 990 | constexpr int void_test = (Void(0), 1); |
991 | |||
992 | namespace PR19741 { | ||
993 | constexpr void addone(int &m) { m++; } | ||
994 | |||
995 | struct S { | ||
996 | int m = 0; | ||
997 | constexpr S() { addone(m); } | ||
998 | }; | ||
999 | constexpr bool evalS() { | ||
1000 | constexpr S s; | ||
1001 | return s.m == 1; | ||
1002 | } | ||
1003 | static_assert(evalS(), ""); | ||
1004 | |||
1005 | struct 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 | }; | ||
1018 | constexpr bool evalNested() { | ||
1019 | constexpr Nested N; | ||
1020 | return N.first.x == 43; | ||
1021 | } | ||
1022 | static_assert(evalNested(), ""); | ||
1023 | } // namespace PR19741 | ||