This revision was automatically updated to reflect the committed changes.
Closed by commit rG180581cfcf51: [clang] Add support for consteval constructors 
(authored by Tyker).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Changed prior to commit:
  https://reviews.llvm.org/D74007?vs=242881&id=251596#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74007/new/

https://reviews.llvm.org/D74007

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===================================================================
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -260,6 +260,19 @@
 
 }
 
+namespace std {
+
+template <typename T> struct remove_reference { using type = T; };
+template <typename T> struct remove_reference<T &> { using type = T; };
+template <typename T> struct remove_reference<T &&> { using type = T; };
+
+template <typename T>
+constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {
+  return static_cast<typename std::remove_reference<T>::type &&>(t);
+}
+
+}
+
 namespace temporaries {
 
 struct A {
@@ -295,12 +308,12 @@
   { int k = const_a_ref(A()); }
   { int k = const_a_ref(a); }
   { int k = rvalue_ref(A()); }
-  { int k = rvalue_ref(static_cast<const A&&>(a)); }
+  { int k = rvalue_ref(std::move(a)); }
   { int k = const_a_ref(A().ret_a()); }
   { int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
-  { int k = const_a_ref(to_lvalue_ref(static_cast<const A&&>(a))); }
+  { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
   { int k = by_value_a(A().ret_a()); }
-  { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
+  { int k = by_value_a(to_lvalue_ref(std::move(a))); }
   { int k = (A().ret_a(), A().ret_i()); }
   { int k = (const_a_ref(A().ret_a()), A().ret_i()); }//
 }
@@ -353,10 +366,10 @@
   { int k = const_a_ref(A()); }
   { int k = const_a_ref(a); }
   { int k = rvalue_ref(A()); }
-  { int k = rvalue_ref(static_cast<const A&&>(a)); }
+  { int k = rvalue_ref(std::move(a)); }
   { int k = const_a_ref(A().ret_a()); }
   { int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
-  { int k = const_a_ref(to_lvalue_ref(static_cast<const A&&>(a))); }
+  { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
   { int k = by_value_a(A().ret_a()); }
   { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
   { int k = (A().ret_a(), A().ret_i()); }// expected-error {{is not a constant expression}}
@@ -388,6 +401,27 @@
   // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
 }
 
+struct S1 {
+  S1* ptr = nullptr;
+  consteval S1(int i) : ptr(this) {
+    if (this == ptr && i)
+      ptr = nullptr;
+  }
+  constexpr ~S1() {}
+};
+
+void test1() {
+  S1 s(1);
+  s = S1(1);
+  s = S1(0); // expected-error {{is not a constant expression}}
+  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
+}
+
+}
+namespace ctor {
+
+consteval int f_eval() { // expected-note+ {{declared here}}
+  return 0;
 }
 
 namespace std {
@@ -441,3 +475,103 @@
     };
   }
 }
+
+struct A {
+  int(*ptr)();
+  consteval A(int(*p)() = nullptr) : ptr(p) {}
+};
+
+struct B {
+  int(*ptr)();
+  B() : ptr(nullptr) {}
+  consteval B(int(*p)(), int) : ptr(p) {}
+};
+
+void test() {
+  { A a; }
+  { A a(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B b(nullptr, 0); }
+  { B b(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A a{}; }
+  { A a{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B b{nullptr, 0}; }
+  { B b{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A a = A(); }
+  { A a = A(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B b = B(nullptr, 0); }
+  { B b = B(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A a = A{}; }
+  { A a = A{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B b = B{nullptr, 0}; }
+  { B b = B{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A a; a = A(); }
+  { A a; a = A(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B b; b = B(nullptr, 0); }
+  { B b; b = B(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A a; a = A{}; }
+  { A a; a = A{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B b; b = B{nullptr, 0}; }
+  { B b; b = B{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A* a; a = new A(); }
+  { A* a; a = new A(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B* b; b = new B(nullptr, 0); }
+  { B* b; b = new B(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { A* a; a = new A{}; }
+  { A* a; a = new A{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { B* b; b = new B{nullptr, 0}; }
+  { B* b; b = new B{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+}
+
+}
+
+namespace copy_ctor {
+
+consteval int f_eval() { // expected-note+ {{declared here}}
+  return 0;
+}
+
+struct Copy {
+  int(*ptr)();
+  constexpr Copy(int(*p)() = nullptr) : ptr(p) {}
+  consteval Copy(const Copy&) = default;
+};
+
+constexpr const Copy &to_lvalue_ref(const Copy &&a) {
+  return a;
+}
+
+void test() {
+  constexpr const Copy C;
+  // there is no the copy constructor call when its argument is a prvalue because of garanteed copy elision.
+  // so we need to test with both prvalue and xvalues.
+  { Copy c(C); }
+  { Copy c((Copy(&f_eval))); }// expected-error {{cannot take address of consteval}}
+  { Copy c(std::move(C)); }
+  { Copy c(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c(to_lvalue_ref((Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c(to_lvalue_ref(std::move(C))); }
+  { Copy c(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c = Copy(C); }
+  { Copy c = Copy(Copy(&f_eval)); }// expected-error {{cannot take address of consteval}}
+  { Copy c = Copy(std::move(C)); }
+  { Copy c = Copy(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c = Copy(to_lvalue_ref(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c = Copy(to_lvalue_ref(std::move(C))); }
+  { Copy c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c; c = Copy(C); }
+  { Copy c; c = Copy(Copy(&f_eval)); }// expected-error {{cannot take address of consteval}}
+  { Copy c; c = Copy(std::move(C)); }
+  { Copy c; c = Copy(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c; c = Copy(to_lvalue_ref(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy c; c = Copy(to_lvalue_ref(std::move(C))); }
+  { Copy c; c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy* c; c = new Copy(C); }
+  { Copy* c; c = new Copy(Copy(&f_eval)); }// expected-error {{cannot take address of consteval}}
+  { Copy* c; c = new Copy(std::move(C)); }
+  { Copy* c; c = new Copy(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy* c; c = new Copy(to_lvalue_ref(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+  { Copy* c; c = new Copy(to_lvalue_ref(std::move(C))); }
+  { Copy* c; c = new Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
+}
+
+} // namespace special_ctor
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -157,6 +157,13 @@
   /// existing lambdas.
   bool ReplacingOriginal() { return false; }
 
+  /// Wether CXXConstructExpr can be skipped when they are implicit.
+  /// They will be reconstructed when used if needed.
+  /// This is usefull when the user that cause rebuilding of the
+  /// CXXConstructExpr is outside of the expression at which the TreeTransform
+  /// started.
+  bool AllowSkippingCXXConstructExpr() { return true; }
+
   /// Returns the location of the entity being transformed, if that
   /// information was not available elsewhere in the AST.
   ///
@@ -11658,10 +11665,11 @@
   // CXXConstructExprs other than for list-initialization and
   // CXXTemporaryObjectExpr are always implicit, so when we have
   // a 1-argument construction we just transform that argument.
-  if ((E->getNumArgs() == 1 ||
-       (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
-      (!getDerived().DropCallArgument(E->getArg(0))) &&
-      !E->isListInitialization())
+  if (getDerived().AllowSkippingCXXConstructExpr() &&
+      ((E->getNumArgs() == 1 ||
+        (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
+       (!getDerived().DropCallArgument(E->getArg(0))) &&
+       !E->isListInitialization()))
     return getDerived().TransformExpr(E->getArg(0));
 
   TemporaryBase Rebase(*this, /*FIXME*/ E->getBeginLoc(), DeclarationName());
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6434,12 +6434,14 @@
     }
     S.MarkFunctionReferenced(Loc, Constructor);
 
-    CurInit = CXXTemporaryObjectExpr::Create(
-        S.Context, Constructor,
-        Entity.getType().getNonLValueExprType(S.Context), TSInfo,
-        ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
-        IsListInitialization, IsStdInitListInitialization,
-        ConstructorInitRequiresZeroInit);
+    CurInit = S.CheckForImmediateInvocation(
+        CXXTemporaryObjectExpr::Create(
+            S.Context, Constructor,
+            Entity.getType().getNonLValueExprType(S.Context), TSInfo,
+            ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
+            IsListInitialization, IsStdInitListInitialization,
+            ConstructorInitRequiresZeroInit),
+        Constructor);
   } else {
     CXXConstructExpr::ConstructionKind ConstructKind =
       CXXConstructExpr::CK_Complete;
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -15403,6 +15403,8 @@
                                            SemaRef.getASTContext(), true);
   if (!Result || !Notes.empty()) {
     Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit();
+    if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr))
+      InnerExpr = FunctionalCast->getSubExpr();
     FunctionDecl *FD = nullptr;
     if (auto *Call = dyn_cast<CallExpr>(InnerExpr))
       FD = cast<FunctionDecl>(Call->getCalleeDecl());
@@ -15473,8 +15475,25 @@
     }
     bool AlwaysRebuild() { return false; }
     bool ReplacingOriginal() { return true; }
+    bool AllowSkippingCXXConstructExpr() {
+      bool Res = AllowSkippingFirstCXXConstructExpr;
+      AllowSkippingFirstCXXConstructExpr = true;
+      return Res;
+    }
+    bool AllowSkippingFirstCXXConstructExpr = true;
   } Transformer(SemaRef, Rec.ReferenceToConsteval,
                 Rec.ImmediateInvocationCandidates, It);
+
+  /// CXXConstructExpr with a single argument are getting skipped by
+  /// TreeTransform in some situtation because they could be implicit. This
+  /// can only occur for the top-level CXXConstructExpr because it is used
+  /// nowhere in the expression being transformed therefore will not be rebuilt.
+  /// Setting AllowSkippingFirstCXXConstructExpr to false will prevent from
+  /// skipping the first CXXConstructExpr.
+  if (auto *OldExpr =
+          dyn_cast<CXXConstructExpr>(It->getPointer()->IgnoreImplicit()))
+    Transformer.AllowSkippingFirstCXXConstructExpr = false;
+
   ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr());
   assert(Res.isUsable());
   Res = SemaRef.MaybeCreateExprWithCleanups(Res);
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -14762,12 +14762,14 @@
   if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor))
     return ExprError();
 
-  return CXXConstructExpr::Create(
-      Context, DeclInitType, ConstructLoc, Constructor, Elidable,
-      ExprArgs, HadMultipleCandidates, IsListInitialization,
-      IsStdInitListInitialization, RequiresZeroInit,
-      static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
-      ParenRange);
+  return CheckForImmediateInvocation(
+      CXXConstructExpr::Create(
+          Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
+          HadMultipleCandidates, IsListInitialization,
+          IsStdInitListInitialization, RequiresZeroInit,
+          static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
+          ParenRange),
+      Constructor);
 }
 
 ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2466,7 +2466,7 @@
   "cannot take address of consteval function %0 outside"
   " of an immediate invocation">;
 def err_invalid_consteval_call : Error<
-  "call to consteval function '%q0' is not a constant expression">;
+  "call to consteval function %q0 is not a constant expression">;
 def err_invalid_consteval_decl_kind : Error<
   "%0 cannot be declared consteval">;
 def err_invalid_constexpr : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to