[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