usaxena95 updated this revision to Diff 451333.
usaxena95 added a comment.

Added tests for multiple constructors in a templated class.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D131479

Files:
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
  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
@@ -766,3 +766,89 @@
   static_assert(c == 8);
 }
 }
+
+namespace defaulted_special_member_template {
+template <typename T>
+struct default_ctor {
+  T data;
+  consteval default_ctor() = default; // expected-note {{non-constexpr constructor 'foo' cannot be used in a constant expression}}
+};
+
+template <typename T>
+struct copy {
+  T data;
+
+  consteval copy(const copy &) = default;            // expected-note {{non-constexpr constructor 'foo' cannot be used in a constant expression}}
+  consteval copy &operator=(const copy &) = default; // expected-note {{non-constexpr function 'operator=' cannot be used in a constant expression}}
+  copy() = default;
+};
+
+template <typename T>
+struct move {
+  T data;
+
+  consteval move(move &&) = default;            // expected-note {{non-constexpr constructor 'foo' cannot be used in a constant expression}}
+  consteval move &operator=(move &&) = default; // expected-note {{non-constexpr function 'operator=' cannot be used in a constant expression}}
+  move() = default;
+};
+
+struct foo {
+  foo() {}            // expected-note {{declared here}}
+  foo(const foo &) {} // expected-note {{declared here}}
+  foo(foo &&) {}      // expected-note {{declared here}}
+
+  foo& operator=(const foo &) { return *this; } // expected-note {{declared here}}
+  foo& operator=(foo &&) { return *this; }      // expected-note {{declared here}}
+};
+
+void func() {
+  default_ctor<foo> fail0; // expected-error-re {{call to consteval function '{{.*::default_ctor<.*::foo>}}::default_ctor' is not a constant expression}} \
+                              expected-note {{in call to 'default_ctor()'}}
+
+  copy<foo> good0;
+  copy<foo> fail1{good0}; // expected-error-re {{call to consteval function '{{.*::copy<.*::foo>}}::copy' is not a constant expression}} \
+                             expected-note {{in call to 'copy(good0)'}}
+  fail1 = good0;          // expected-error-re {{call to consteval function '{{.*::copy<.*::foo>}}::operator=' is not a constant expression}} \
+                             expected-note {{in call to '&fail1->operator=(good0)'}}
+
+  move<foo> good1;
+  move<foo> fail2{static_cast<move<foo>&&>(good1)}; // expected-error-re {{call to consteval function '{{.*::move<.*::foo>}}::move' is not a constant expression}} \
+                                                       expected-note {{in call to 'move(good1)'}}
+  fail2 = static_cast<move<foo>&&>(good1);          // expected-error-re {{call to consteval function '{{.*::move<.*::foo>}}::operator=' is not a constant expression}} \
+                                                       expected-note {{in call to '&fail2->operator=(good1)'}}
+}
+} // namespace defaulted_special_member_template
+
+namespace multiple_default_constructors {
+struct Foo {
+  Foo() {}; // expected-note {{declared here}}
+};
+struct Bar {
+  Bar() = default;
+};
+struct Baz {
+  consteval Baz() {}
+};
+
+template <typename T, unsigned N>
+struct S {
+  T data;
+  S() requires (N==1) = default;
+  S() requires (N==2) {}
+  consteval S() requires (N==3) = default;  // expected-note {{non-constexpr constructor 'Foo' cannot be used in a constant expression}}
+};
+
+void func() {
+  // Explictly defaulted constructor.
+  S<Foo, 1> s1;
+  S<Bar, 1> s2;
+  // User provided constructor.
+  S<Foo, 2> s3;
+  S<Bar, 2> s4;
+  // Consteval explictly defaulted constructor.
+  S<Foo, 3> s5; // expected-error-re {{call to consteval function '{{.*}}::S<{{.*}}::Foo, 3>::S' is not a constant expression}} \
+                   expected-note {{in call to 'S()'}}
+  S<Bar, 3> s6;
+  S<Baz, 3> s7;
+}
+} // namespace multiple_default_constructors
Index: clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
===================================================================
--- clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -44,18 +44,20 @@
 }
 
 template<typename T> struct S : T {
-  constexpr S() = default;
-  constexpr S(const S&) = default;
-  constexpr S(S&&) = default;
+  constexpr S() = default;         // expected-note {{previous declaration is here}}
+  constexpr S(const S&) = default; // expected-note {{previous declaration is here}}
+  constexpr S(S&&) = default;      // expected-note {{previous declaration is here}}
 };
 struct lit { constexpr lit() {} };
 S<lit> s_lit; // ok
 S<bar> s_bar; // ok
 
 struct Friends {
-  friend S<bar>::S();
-  friend S<bar>::S(const S&);
-  friend S<bar>::S(S&&);
+  // FIXME: these error may or may not be correct; there is an open question on
+  // the CWG reflectors about this.
+  friend S<bar>::S();          // expected-error {{non-constexpr declaration of 'S' follows constexpr declaration}}
+  friend S<bar>::S(const S&);  // expected-error {{non-constexpr declaration of 'S' follows constexpr declaration}}
+  friend S<bar>::S(S&&);       // expected-error {{non-constexpr declaration of 'S' follows constexpr declaration}}
 };
 
 namespace DefaultedFnExceptionSpec {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/EvaluatedExprVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecordLayout.h"
@@ -7202,10 +7203,24 @@
 static bool defaultedSpecialMemberIsConstexpr(
     Sema &S, CXXRecordDecl *ClassDecl, Sema::CXXSpecialMember CSM,
     bool ConstArg, CXXConstructorDecl *InheritedCtor = nullptr,
-    Sema::InheritedConstructorInfo *Inherited = nullptr) {
+    Sema::InheritedConstructorInfo *Inherited = nullptr,
+    CXXMethodDecl *SpecialMemberDecl = nullptr) {
   if (!S.getLangOpts().CPlusPlus11)
     return false;
 
+  // C++14 [dcl.constexpr]p6 (CWG DR647/CWG DR1358):
+  //   If the instantiated template specialization of a constexpr function
+  //   template or member function of a class template would fail to satisfy
+  //   the requirements for a constexpr function or constexpr constructor, that
+  //   specialization is still a constexpr function or constexpr constructor,
+  //   even though a call to such a function cannot appear in a constant
+  //   expression.
+  if (SpecialMemberDecl &&
+      (isa<ClassTemplateSpecializationDecl>(ClassDecl) ||
+        SpecialMemberDecl->isFunctionTemplateSpecialization())
+        && SpecialMemberDecl->isConstexpr())
+    return true;
+
   // C++11 [dcl.constexpr]p4:
   // In the definition of a constexpr constructor [...]
   bool Ctor = true;
@@ -7537,8 +7552,8 @@
   // destructors in C++14 and C++17), this is checked elsewhere.
   //
   // FIXME: This should not apply if the member is deleted.
-  bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
-                                                     HasConstParam);
+  bool Constexpr = defaultedSpecialMemberIsConstexpr(
+      *this, RD, CSM, HasConstParam, nullptr, nullptr, MD);
   if ((getLangOpts().CPlusPlus20 ||
        (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
                                   : isa<CXXConstructorDecl>(MD))) &&
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to