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@-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@-1 {{'UBar' declared here}} - void foo1(); // expected-error {{a non-type template parameter cannot have type 'class UBar'}} + // expected-note@-2 {{forward declaration of 'UBar'}} + void foo1(); // expected-error {{non-type template parameter has incomplete type 'class UBar'}} // expected-error@-1 {{expected ',' or '>' in template-parameter-list}} // expected-error@-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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits