[clang] 0cd73db - [c++20] For P1907R1: Add checking for structural types for non-type

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 20 20:21:06 PDT 2020


Author: Richard Smith
Date: 2020-09-20T20:20:52-07:00
New Revision: 0cd73dbe2c0d169ec2cdd9a8264f4ee1695b53b7

URL: https://github.com/llvm/llvm-project/commit/0cd73dbe2c0d169ec2cdd9a8264f4ee1695b53b7
DIFF: https://github.com/llvm/llvm-project/commit/0cd73dbe2c0d169ec2cdd9a8264f4ee1695b53b7.diff

LOG: [c++20] For P1907R1: Add checking for structural types for non-type
template parameters.

No support for the new kinds of non-type template argument yet.

This is not entirely NFC for prior language modes: we have historically
incorrectly accepted rvalue references as the types of non-type template
parameters. Such invalid code is now rejected.

Added: 
    clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

Modified: 
    clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
    clang/include/clang/AST/DeclCXX.h
    clang/include/clang/AST/Type.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/DeclCXX.cpp
    clang/lib/AST/Type.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/test/CXX/temp/temp.param/p7.cpp
    clang/test/CodeGenCXX/debug-info-template.cpp
    clang/test/SemaCXX/invalid-template-params.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
index 33e65f8ebf44..4ce6771259d9 100644
--- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
+++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
@@ -210,6 +210,9 @@ FIELD(DefaultedDestructorIsConstexpr, 1, NO_MERGE)
 /// member or base class of non-literal or volatile type.
 FIELD(HasNonLiteralTypeFieldsOrBases, 1, NO_MERGE)
 
+/// True if this class is a structural type, assuming it is a literal type.
+FIELD(StructuralIfLiteral, 1, NO_MERGE)
+
 /// Whether we have a C++11 user-provided default constructor (not
 /// explicitly deleted or defaulted).
 FIELD(UserProvidedDefaultConstructor, 1, NO_MERGE)

diff  --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 20f058b87e7f..da5ae0fa999d 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1396,6 +1396,11 @@ class CXXRecordDecl : public RecordDecl {
             hasTrivialDefaultConstructor());
   }
 
+  /// Determine whether this is a structural type.
+  bool isStructural() const {
+    return isLiteral() && data().StructuralIfLiteral;
+  }
+
   /// If this record is an instantiation of a member class,
   /// retrieves the member class from which it was instantiated.
   ///

diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index d8eece10475a..d16edf8a6b12 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1927,6 +1927,9 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
   /// (C++11 [basic.types]p10)
   bool isLiteralType(const ASTContext &Ctx) const;
 
+  /// Determine if this type is a structural type, per C++20 [temp.param]p7.
+  bool isStructuralType() const;
+
   /// Test if this type is a standard-layout type.
   /// (C++0x [basic.type]p9)
   bool isStandardLayoutType() const;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2e265e114191..053aae7a6afa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4423,6 +4423,28 @@ def note_template_nontype_parm_prev_declaration : Note<
   "previous non-type template parameter with type %0 is here">;
 def err_template_nontype_parm_bad_type : Error<
   "a non-type template parameter cannot have type %0">;
+def err_template_nontype_parm_bad_structural_type : Error<
+  "a non-type template parameter cannot have type %0 before C++20">;
+def err_template_nontype_parm_incomplete : Error<
+  "non-type template parameter has incomplete type %0">;
+def err_template_nontype_parm_not_literal : Error<
+  "non-type template parameter has non-literal type %0">;
+def err_template_nontype_parm_rvalue_ref : Error<
+  "non-type template parameter has rvalue reference type %0">;
+def err_template_nontype_parm_not_structural : Error<
+  "type %0 of non-type template parameter is not a structural type">;
+def note_not_structural_non_public : Note<
+  "%0 is not a structural type because it has a "
+  "%select{non-static data member|base class}1 that is not public">;
+def note_not_structural_mutable_field : Note<
+  "%0 is not a structural type because it has a mutable "
+  "non-static data member">;
+def note_not_structural_rvalue_ref_field : Note<
+  "%0 is not a structural type because it has a non-static data member "
+  "of rvalue reference type">;
+def note_not_structural_subobject : Note<
+  "%0 is not a structural type because it has a "
+  "%select{non-static data member|base class}1 of non-structural type %2">;
 def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
   "non-type template parameters declared with %0 are incompatible with C++ "
   "standards before C++17">,
@@ -4542,6 +4564,8 @@ def err_non_type_template_arg_subobject : Error<
   "non-type template argument refers to subobject '%0'">;
 def err_non_type_template_arg_addr_label_
diff  : Error<
   "template argument / label address 
diff erence / what did you expect?">;
+def err_non_type_template_arg_unsupported : Error<
+  "sorry, non-type template argument of type %0 is not yet supported">;
 def err_template_arg_not_convertible : Error<
   "non-type template argument of type %0 cannot be converted to a value "
   "of type %1">;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e05ff2e3a9ac..12943f2bd5bd 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7238,6 +7238,8 @@ class Sema final {
                             NonTypeTemplateParmDecl *ConstrainedParameter,
                             SourceLocation EllipsisLoc);
 
+  bool RequireStructuralType(QualType T, SourceLocation Loc);
+
   QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
                                              SourceLocation Loc);
   QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);

diff  --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 59ae5cb300f7..88ca7cf11606 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -100,7 +100,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
       DefaultedDefaultConstructorIsConstexpr(true),
       HasConstexprDefaultConstructor(false),
       DefaultedDestructorIsConstexpr(true),
-      HasNonLiteralTypeFieldsOrBases(false),
+      HasNonLiteralTypeFieldsOrBases(false), StructuralIfLiteral(true),
       UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
       ImplicitCopyConstructorCanHaveConstParamForVBase(true),
       ImplicitCopyConstructorCanHaveConstParamForNonVBase(true),
@@ -258,9 +258,15 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
 
     // C++1z [dcl.init.agg]p1:
     //   An aggregate is a class with [...] no private or protected base classes
-    if (Base->getAccessSpecifier() != AS_public)
+    if (Base->getAccessSpecifier() != AS_public) {
       data().Aggregate = false;
 
+      // C++20 [temp.param]p7:
+      //   A structural type is [...] a literal class type with [...] all base
+      //   classes [...] public
+      data().StructuralIfLiteral = false;
+    }
+
     // C++ [class.virtual]p1:
     //   A class that declares or inherits a virtual function is called a
     //   polymorphic class.
@@ -536,6 +542,13 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
   //      array thereof, that class type shall have a constexpr destructor
   if (!Subobj->hasConstexprDestructor())
     data().DefaultedDestructorIsConstexpr = false;
+
+  // C++20 [temp.param]p7:
+  //   A structural type is [...] a literal class type [for which] the types
+  //   of all base classes and non-static data members are structural types or
+  //   (possibly multi-dimensional) array thereof
+  if (!Subobj->data().StructuralIfLiteral)
+    data().StructuralIfLiteral = false;
 }
 
 bool CXXRecordDecl::hasConstexprDestructor() const {
@@ -956,6 +969,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
     if (D->getAccess() == AS_private || D->getAccess() == AS_protected) {
       data().Aggregate = false;
       data().PlainOldData = false;
+
+      // C++20 [temp.param]p7:
+      //   A structural type is [...] a literal class type [for which] all
+      //   non-static data members are public
+      data().StructuralIfLiteral = false;
     }
 
     // Track whether this is the first field. We use this when checking
@@ -980,9 +998,15 @@ void CXXRecordDecl::addedMember(Decl *D) {
     }
 
     // Keep track of the presence of mutable fields.
-    if (Field->isMutable())
+    if (Field->isMutable()) {
       data().HasMutableFields = true;
 
+      // C++20 [temp.param]p7:
+      //   A structural type is [...] a literal class type [for which] all
+      //   non-static data members are public
+      data().StructuralIfLiteral = false;
+    }
+
     // C++11 [class.union]p8, DR1460:
     //   If X is a union, a non-static data member of X that is not an anonymous
     //   union is a variant member of X.
@@ -1315,6 +1339,14 @@ void CXXRecordDecl::addedMember(Decl *D) {
         data().DefaultedCopyAssignmentIsDeleted = true;
         data().DefaultedMoveAssignmentIsDeleted = true;
       }
+
+      // C++20 [temp.param]p7:
+      //   A structural type is [...] a literal class type [for which] the
+      //   types of all non-static data members are structural types or
+      //   (possibly multidimensional) array thereof
+      // We deal with class types elsewhere.
+      if (!T->isScalarType() && !T->isLValueReferenceType())
+        data().StructuralIfLiteral = false;
     }
 
     // C++14 [meta.unary.prop]p4:

diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index ff73a7340091..8a47b75ac88a 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2596,6 +2596,21 @@ bool Type::isLiteralType(const ASTContext &Ctx) const {
   return false;
 }
 
+bool Type::isStructuralType() const {
+  // C++20 [temp.param]p6:
+  //   A structural type is one of the following:
+  //   -- a scalar type; or
+  if (isScalarType())
+    return true;
+  //   -- an lvalue reference type; or
+  if (isLValueReferenceType())
+    return true;
+  //  -- a literal class type [...under some conditions]
+  if (const CXXRecordDecl *RD = getAsCXXRecordDecl())
+    return RD->isStructural();
+  return false;
+}
+
 bool Type::isStandardLayoutType() const {
   if (isDependentType())
     return false;

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index e1a563850970..b126fd9c8006 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1278,6 +1278,108 @@ QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
   return CheckNonTypeTemplateParameterType(TSI->getType(), Loc);
 }
 
+/// Require the given type to be a structural type, and diagnose if it is not.
+///
+/// \return \c true if an error was produced.
+bool Sema::RequireStructuralType(QualType T, SourceLocation Loc) {
+  if (T->isDependentType())
+    return false;
+
+  if (RequireCompleteType(Loc, T, diag::err_template_nontype_parm_incomplete))
+    return true;
+
+  if (T->isStructuralType())
+    return false;
+
+  // Structural types are required to be object types or lvalue references.
+  if (T->isRValueReferenceType()) {
+    Diag(Loc, diag::err_template_nontype_parm_rvalue_ref) << T;
+    return true;
+  }
+
+  // Don't mention structural types in our diagnostic prior to C++20. Also,
+  // there's not much more we can say about non-scalar non-class types --
+  // because we can't see functions or arrays here, those can only be language
+  // extensions.
+  if (!getLangOpts().CPlusPlus20 ||
+      (!T->isScalarType() && !T->isRecordType())) {
+    Diag(Loc, diag::err_template_nontype_parm_bad_type) << T;
+    return true;
+  }
+
+  // Structural types are required to be literal types.
+  if (RequireLiteralType(Loc, T, diag::err_template_nontype_parm_not_literal))
+    return true;
+
+  Diag(Loc, diag::err_template_nontype_parm_not_structural) << T;
+
+  // Drill down into the reason why the class is non-structural.
+  while (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+    // All members are required to be public and non-mutable, and can't be of
+    // rvalue reference type. Check these conditions first to prefer a "local"
+    // reason over a more distant one.
+    for (const FieldDecl *FD : RD->fields()) {
+      if (FD->getAccess() != AS_public) {
+        Diag(FD->getLocation(), diag::note_not_structural_non_public) << T << 0;
+        return true;
+      }
+      if (FD->isMutable()) {
+        Diag(FD->getLocation(), diag::note_not_structural_mutable_field) << T;
+        return true;
+      }
+      if (FD->getType()->isRValueReferenceType()) {
+        Diag(FD->getLocation(), diag::note_not_structural_rvalue_ref_field)
+            << T;
+        return true;
+      }
+    }
+
+    // All bases are required to be public.
+    for (const auto &BaseSpec : RD->bases()) {
+      if (BaseSpec.getAccessSpecifier() != AS_public) {
+        Diag(BaseSpec.getBaseTypeLoc(), diag::note_not_structural_non_public)
+            << T << 1;
+        return true;
+      }
+    }
+
+    // All subobjects are required to be of structural types.
+    SourceLocation SubLoc;
+    QualType SubType;
+    int Kind = -1;
+
+    for (const FieldDecl *FD : RD->fields()) {
+      QualType T = Context.getBaseElementType(FD->getType());
+      if (!T->isStructuralType()) {
+        SubLoc = FD->getLocation();
+        SubType = T;
+        Kind = 0;
+        break;
+      }
+    }
+
+    if (Kind == -1) {
+      for (const auto &BaseSpec : RD->bases()) {
+        QualType T = BaseSpec.getType();
+        if (!T->isStructuralType()) {
+          SubLoc = BaseSpec.getBaseTypeLoc();
+          SubType = T;
+          Kind = 1;
+          break;
+        }
+      }
+    }
+
+    assert(Kind != -1 && "couldn't find reason why type is not structural");
+    Diag(SubLoc, diag::note_not_structural_subobject)
+        << T << Kind << SubType;
+    T = SubType;
+    RD = T->getAsCXXRecordDecl();
+  }
+
+  return true;
+}
+
 QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
                                                  SourceLocation Loc) {
   // We don't allow variably-modified types as the type of non-type template
@@ -1297,13 +1399,13 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
   if (T->isIntegralOrEnumerationType() ||
       //   -- pointer to object or pointer to function,
       T->isPointerType() ||
-      //   -- reference to object or reference to function,
-      T->isReferenceType() ||
+      //   -- lvalue reference to object or lvalue reference to function,
+      T->isLValueReferenceType() ||
       //   -- pointer to member,
       T->isMemberPointerType() ||
-      //   -- std::nullptr_t.
+      //   -- std::nullptr_t, or
       T->isNullPtrType() ||
-      // Allow use of auto in template parameter declarations.
+      //   -- a type that contains a placeholder type.
       T->isUndeducedType()) {
     // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
     // are ignored when determining its type.
@@ -1327,10 +1429,20 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
   if (T->isDependentType())
     return T.getUnqualifiedType();
 
-  Diag(Loc, diag::err_template_nontype_parm_bad_type)
-    << T;
+  // C++20 [temp.param]p6:
+  //   -- a structural type
+  if (RequireStructuralType(T, Loc))
+    return QualType();
 
-  return QualType();
+  if (!getLangOpts().CPlusPlus20) {
+    // FIXME: Consider allowing structural types as an extension in C++17. (In
+    // earlier language modes, the template argument evaluation rules are too
+    // inflexible.)
+    Diag(Loc, diag::err_template_nontype_parm_bad_structural_type) << T;
+    return QualType();
+  }
+
+  return T.getUnqualifiedType();
 }
 
 NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
@@ -6866,6 +6978,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
         return ExprError();
       }
       // -- a subobject
+      // FIXME: Until C++20
       if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
           VD && VD->getType()->isArrayType() &&
           Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
@@ -6897,7 +7010,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     case APValue::Array:
     case APValue::Struct:
     case APValue::Union:
-      llvm_unreachable("invalid kind for template argument");
+      return Diag(StartLoc, diag::err_non_type_template_arg_unsupported)
+             << ParamType;
     }
 
     return ArgResult.get();

diff  --git a/clang/test/CXX/temp/temp.param/p7.cpp b/clang/test/CXX/temp/temp.param/p7.cpp
index 13f0367764aa..bc203a8ad2ff 100644
--- a/clang/test/CXX/temp/temp.param/p7.cpp
+++ b/clang/test/CXX/temp/temp.param/p7.cpp
@@ -1,15 +1,126 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 -std=c++98 %s -Wno-c++11-extensions
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
 
+// C++98:
 // A non-type template-parameter shall not be declared to have
 // floating point, class, or void type.
-struct A;
+struct A; // expected-note {{forward declaration}}
 
-template<double d> class X; // expected-error{{cannot have type}}
+template<double d> class X; // cxx17-error{{cannot have type}}
 template<double* pd> class Y; //OK 
 template<double& rd> class Z; //OK 
 
-template<A a> class X0; // expected-error{{cannot have type}}
+template<A a> class X0; // expected-error{{has incomplete type 'A'}}
+
+struct A {};
+
+template<A a> class X0b; // cxx17-error{{cannot have type 'A' before C++20}}
 
 typedef void VOID;
-template<VOID a> class X01; // expected-error{{cannot have type}}
+template<VOID a> class X01; // expected-error{{has incomplete type 'VOID'}}
+
+// C++11 disallows rvalue references.
+
+template<int &R> struct lval_ref;
+template<int &&R> struct rval_ref; // expected-warning 0-1{{extension}} expected-error {{non-type template parameter has rvalue reference type 'int &&'}}
+
+// C++20 requires a structural type. In addition to the above cases, this allows:
+
+// arbitrary scalar types; we generally include complex types in that list
+template<_Complex float ci> struct ComplexFloat; // cxx17-error {{cannot have type '_Complex float' before C++20}}
+template<_Complex int ci> struct ComplexInt; // cxx17-error {{cannot have type '_Complex int' before C++20}}
+template<_ExtInt(42) ei> struct ExtInt;
+
+// atomic and vector types aren't scalar types
+// FIXME: Consider permitting vector types here.
+template<_Atomic float ci> struct AtomicFloat; // expected-error {{cannot have type '_Atomic(float)'}}
+template<_Atomic int ci> struct AtomicInt; // expected-error {{cannot have type '_Atomic(int)'}}
+
+typedef __attribute__((ext_vector_type(4))) int VI4;
+typedef __attribute__((ext_vector_type(4))) float VF4;
+template<VI4> struct VectorInt; // expected-error {{cannot have type 'VI4'}}
+template<VF4> struct VectorFloat; // expected-error {{cannot have type 'VF4'}}
+
+struct A2 {};
+
+struct RRef {
+  int &&r; // cxx20-note 1+{{'RRef' is not a structural type because it has a non-static data member of rvalue reference type}}
+};
+
+// class types with all public members and bases, no mutable state, and no rvalue references.
+struct B : A, public A2 {
+  int a;
+private:
+  void f();
+  static int s;
+public:
+  float g;
+  int &r = a;
+  void *p;
+  A2 a2;
+  RRef *ptr_to_bad;
+  RRef &ref_to_bad = *ptr_to_bad;
+  _Complex int ci;
+  _Complex float cf;
+  _ExtInt(42) ei;
+};
+
+template<B> struct ClassNTTP {}; // cxx17-error {{cannot have type 'B'}}
+
+template<RRef> struct WithRRef {}; // cxx17-error {{cannot have type 'RRef'}}
+// cxx20-error at -1 {{type 'RRef' of non-type template parameter is not a structural type}}
+
+struct BadBase
+  : RRef {}; // cxx20-note {{'BadBase' is not a structural type because it has a base class of non-structural type 'RRef'}}
+template<BadBase> struct WithBadBase {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct BadField {
+  RRef r; // cxx20-note {{'BadField' is not a structural type because it has a non-static data member of non-structural type 'RRef'}}
+};
+template<BadField> struct WithBadField {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct BadFieldArray {
+  RRef r[3][2]; // cxx20-note {{'BadFieldArray' is not a structural type because it has a non-static data member of non-structural type 'RRef'}}
+};
+template<BadFieldArray> struct WithBadFieldArray {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct ProtectedBase
+  : protected A {}; // cxx20-note {{'ProtectedBase' is not a structural type because it has a base class that is not public}}
+template<ProtectedBase> struct WithProtectedBase {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct PrivateBase
+  : private A {}; // cxx20-note {{'PrivateBase' is not a structural type because it has a base class that is not public}}
+template<PrivateBase> struct WithPrivateBase {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+class Private2Base
+  : A {}; // cxx20-note {{'Private2Base' is not a structural type because it has a base class that is not public}}
+template<Private2Base> struct WithPrivate2Base {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct ProtectedField {
+protected:
+  A r; // cxx20-note {{'ProtectedField' is not a structural type because it has a non-static data member that is not public}}
+};
+template<ProtectedField> struct WithProtectedField {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct PrivateField {
+private:
+  A r; // cxx20-note {{'PrivateField' is not a structural type because it has a non-static data member that is not public}}
+};
+template<PrivateField> struct WithPrivateField {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+class Private2Field {
+  A r; // cxx20-note {{'Private2Field' is not a structural type because it has a non-static data member that is not public}}
+};
+template<Private2Field> struct WithPrivate2Field {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+
+struct MutableField {
+  mutable int n; // cxx20-note {{'MutableField' is not a structural type because it has a mutable non-static data member}}
+};
+template<MutableField> struct WithMutableField {}; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
 
+template<typename T> struct BadExtType { T t; }; // cxx20-note 4{{has a non-static data member of non-structural type}}
+template<BadExtType<_Atomic float> > struct AtomicFloatField; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+template<BadExtType<_Atomic int> > struct AtomicInt; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+template<BadExtType<VI4> > struct VectorInt; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}
+template<BadExtType<VF4> > struct VectorFloat; // cxx17-error {{cannot have type}} cxx20-error {{is not a structural type}}

diff  --git a/clang/test/CodeGenCXX/debug-info-template.cpp b/clang/test/CodeGenCXX/debug-info-template.cpp
index a07222ace150..f52380a62ca6 100644
--- a/clang/test/CodeGenCXX/debug-info-template.cpp
+++ b/clang/test/CodeGenCXX/debug-info-template.cpp
@@ -121,7 +121,7 @@ template<typename>
 struct tmpl_impl {
 };
 
-template <template <typename> class tmpl, int &lvr, int &&rvr>
+template <template <typename> class tmpl, int &lvr>
 struct NN {
 };
 
@@ -129,16 +129,14 @@ struct NN {
 // CHECK: [[NNV]] = distinct !DIGlobalVariable(name: "nn"
 // CHECK-SAME:                                 type: ![[NNT:[0-9]+]]
 
-// CHECK: ![[NNT]] ={{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "NN<tmpl_impl, glb, glb>",
+// CHECK: ![[NNT]] ={{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "NN<tmpl_impl, glb>",
 // CHECK-SAME:             templateParams: [[NNARGS:![0-9]*]]
 // CHECK-SAME:             identifier:
-// CHECK: [[NNARGS]] = !{[[NNARG1:![0-9]*]], [[NNARG2:![0-9]*]], [[NNARG3:![0-9]*]]}
+// CHECK: [[NNARGS]] = !{[[NNARG1:![0-9]*]], [[NNARG2:![0-9]*]]}
 // CHECK: [[NNARG1]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_template_param, name: "tmpl", value: !"tmpl_impl")
 // CHECK: [[NNARG2]] = !DITemplateValueParameter(name: "lvr", type: [[INTLVR:![0-9]*]], value: i32* @glb)
 // CHECK: [[INTLVR]] = !DIDerivedType(tag: DW_TAG_reference_type, baseType: [[INT]]
-// CHECK: [[NNARG3]] = !DITemplateValueParameter(name: "rvr", type: [[INTRVR:![0-9]*]], value: i32* @glb)
-// CHECK: [[INTRVR]] = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: [[INT]]
-NN<tmpl_impl, glb, glb> nn;
+NN<tmpl_impl, glb> nn;
 
 // CHECK: ![[PADDINGATEND:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "PaddingAtEnd",
 struct PaddingAtEnd {

diff  --git a/clang/test/SemaCXX/invalid-template-params.cpp b/clang/test/SemaCXX/invalid-template-params.cpp
index 21220f3fea34..6f19aa9d5ddb 100644
--- a/clang/test/SemaCXX/invalid-template-params.cpp
+++ b/clang/test/SemaCXX/invalid-template-params.cpp
@@ -3,7 +3,8 @@
 template<class> class Foo {
   template<class UBar // expected-error {{expected ';' after class}}
                       // expected-note at -1 {{'UBar' declared here}}
-  void foo1(); // expected-error {{a non-type template parameter cannot have type 'class UBar'}}
+                      // expected-note at -2 {{forward declaration of 'UBar'}}
+  void foo1(); // expected-error {{non-type template parameter has incomplete type 'class UBar'}}
                // expected-error at -1 {{expected ',' or '>' in template-parameter-list}}
                // expected-error at -2 {{declaration does not declare anything}}
 };

diff  --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
new file mode 100644
index 000000000000..aa9e71ff1f6e
--- /dev/null
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+// floating-point arguments
+template<float> struct Float {};
+using F1 = Float<1.0f>; // FIXME expected-error {{sorry}}
+using F1 = Float<2.0f / 2>; // FIXME expected-error {{sorry}}
+
+struct S { int n[3]; } s; // expected-note 1+{{here}}
+int n; // expected-note 1+{{here}}
+
+// pointers to subobjects
+template<int *> struct IntPtr {};
+using IPn = IntPtr<&n + 1>; // FIXME expected-error {{refers to subobject}}
+using IPn = IntPtr<&n + 1>; // FIXME expected-error {{refers to subobject}}
+
+using IP2 = IntPtr<&s.n[2]>; // FIXME expected-error {{refers to subobject}}
+using IP2 = IntPtr<s.n + 2>; // FIXME expected-error {{refers to subobject}}
+
+using IP3 = IntPtr<&s.n[3]>; // FIXME expected-error {{refers to subobject}}
+using IP3 = IntPtr<s.n + 3>; // FIXME expected-error {{refers to subobject}}
+
+template<int &> struct IntRef {};
+using IPn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
+using IPn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
+
+using IP2 = IntRef<s.n[2]>; // FIXME expected-error {{refers to subobject}}
+using IP2 = IntRef<*(s.n + 2)>; // FIXME expected-error {{refers to subobject}}
+
+using IP3 = IntRef<s.n[3]>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
+using IP3 = IntRef<*(s.n + 3)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
+
+// classes
+template<S> struct Struct {};
+using S123 = Struct<S{1, 2, 3}>; // FIXME: expected-error {{sorry}}
+using S123 = Struct<S{1, 2, 3}>; // FIXME: expected-error {{sorry}}
+
+// miscellaneous scalar types
+template<_Complex int> struct ComplexInt {};
+using CI = ComplexInt<1 + 3i>; // FIXME: expected-error {{sorry}}
+using CI = ComplexInt<1 + 3i>; // FIXME: expected-error {{sorry}}
+
+template<_Complex float> struct ComplexFloat {};
+using CF = ComplexFloat<1.0f + 3.0fi>; // FIXME: expected-error {{sorry}}
+using CF = ComplexFloat<1.0f + 3.0fi>; // FIXME: expected-error {{sorry}}


        


More information about the cfe-commits mailing list