forked from OSchip/llvm-project
[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.
This commit is contained in:
parent
1d782c2987
commit
0cd73dbe2c
|
@ -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)
|
||||
|
|
|
@ -1396,6 +1396,11 @@ public:
|
|||
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.
|
||||
///
|
||||
|
|
|
@ -1927,6 +1927,9 @@ public:
|
|||
/// (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;
|
||||
|
|
|
@ -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 difference / 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">;
|
||||
|
|
|
@ -7238,6 +7238,8 @@ public:
|
|||
NonTypeTemplateParmDecl *ConstrainedParameter,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
bool RequireStructuralType(QualType T, SourceLocation Loc);
|
||||
|
||||
QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
|
||||
SourceLocation Loc);
|
||||
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
|
|
|
@ -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}}
|
Loading…
Reference in New Issue