Index: include/clang/AST/CanonicalType.h =================================================================== --- include/clang/AST/CanonicalType.h +++ include/clang/AST/CanonicalType.h @@ -265,6 +265,8 @@ // Type predicates LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDefiniteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIndefiniteType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSizelessType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSizelessBuiltinType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType) Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -273,7 +273,7 @@ MLV_DuplicateVectorComponents, MLV_InvalidExpression, MLV_LValueCast, // Specialized form of MLV_InvalidExpression. - MLV_IncompleteType, + MLV_IndefiniteType, MLV_ConstQualified, MLV_ConstQualifiedField, MLV_ConstAddrSpace, @@ -328,7 +328,7 @@ CM_ConstQualifiedField, CM_ConstAddrSpace, CM_ArrayType, - CM_IncompleteType + CM_IndefiniteType }; private: Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1722,6 +1722,20 @@ bool isSizelessType() const; bool isSizelessBuiltinType() const; + /// As an extension, we classify types as one of "definite" or "indefinite"; + /// every type is one or the other. Indefinite types are types that can + /// describe objects but don't have enough information to construct them. + /// This is true iff the type is both "sized" and incomplete according + /// to the standard definition. + /// + /// \brief Def If non-null, and the type refers to some kind of declaration + /// that can be made definite (such as a C struct, C++ class, or Objective-C + /// class), will be set to the declaration. + bool isIndefiniteType(NamedDecl **Def = nullptr) const; + bool isDefiniteType(NamedDecl **Def = nullptr) const { + return !isIndefiniteType(Def); + } + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. @@ -1730,10 +1744,17 @@ /// determine its size (e.g. void, or a fwd declared struct). Clients of this /// routine will need to determine if the size is actually required. /// - /// \brief Def If non-null, and the type refers to some kind of declaration - /// that can be completed (such as a C struct, C++ class, or Objective-C - /// class), will be set to the declaration. - bool isIncompleteType(NamedDecl **Def = nullptr) const; + /// A type is incomplete according to our definition iff: + /// - it is incomplete according to the standard definition; or + /// - it is "sizeless" + /// + /// The intention is that the usual rules for incomplete types will + /// by default apply to sizeless types as well. Specifically-chosen + /// rules can then be redefined in terms of "definite" and "indefinite" + /// if sizeless definite types are acceptable. + bool isIncompleteType() const { + return isIndefiniteType() || isSizelessType(); + } /// Return true if this is an incomplete or object /// type, in other words, not a function type. Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2483,6 +2483,8 @@ "redeclaration has different alignment requirement (%1 vs %0)">; def err_alignas_underaligned : Error< "requested alignment is less than minimum alignment of %1 for type %0">; +def err_attribute_sizeless_type : Error< + "%0 attribute cannot be applied to sizeless type %1">; def err_attribute_argument_n_type : Error< "%0 attribute requires parameter %1 to be %select{int or bool|an integer " "constant|a string|an identifier}2">; @@ -6399,6 +6401,8 @@ "implicit conversion from array size expression of type %0 to " "%select{integral|enumeration}1 type %2 is a C++11 extension">, InGroup; +def err_array_of_sizeless : Error< + "array has sizeless element type %0">; def warn_cxx98_compat_array_size_conversion : Warning< "implicit conversion from array size expression of type %0 to " "%select{integral|enumeration}1 type %2 is incompatible with C++98">, @@ -8205,6 +8209,8 @@ "__block attribute not allowed, only allowed on local variables">; def err_block_on_vm : Error< "__block attribute not allowed on declaration with a variably modified type">; +def err_sizeless_nonlocal : Error< + "non-local variable with sizeless type %0">; def err_vec_builtin_non_vector : Error< "first two arguments to %0 must be vectors">; Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -1023,8 +1023,8 @@ /// \brief Default-initialization of a 'const' object. FK_DefaultInitOfConst, - /// \brief Initialization of an incomplete type. - FK_Incomplete, + /// \brief Initialization of an indefinite type. + FK_Indefinite, /// \brief Variable-length array must not have an initializer. FK_VariableLengthArrayHasInitializer, @@ -1054,8 +1054,8 @@ /// \brief The candidate set created when initialization failed. OverloadCandidateSet FailedCandidateSet; - /// \brief The incomplete type that caused a failure. - QualType FailedIncompleteType; + /// \brief The indefinite type that caused a failure. + QualType FailedIndefiniteType; /// \brief The fixit that needs to be applied to make this initialization /// succeed. @@ -1324,8 +1324,8 @@ void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; this->Failure = Failure; - assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) && - "Incomplete type failure requires a type!"); + assert((Failure != FK_Indefinite || !FailedIndefiniteType.isNull()) && + "Indefinite type failure requires a type!"); } /// \brief Note that this initialization sequence failed due to failed @@ -1345,10 +1345,10 @@ } /// \brief Note that this initialization sequence failed due to an - /// incomplete type. - void setIncompleteTypeFailure(QualType IncompleteType) { - FailedIncompleteType = IncompleteType; - SetFailed(FK_Incomplete); + /// indefinite type. + void setIndefiniteTypeFailure(QualType IndefiniteType) { + FailedIndefiniteType = IndefiniteType; + SetFailed(FK_Indefinite); } /// \brief Determine why initialization failed. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1516,7 +1516,8 @@ }; private: - bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, + bool RequireDefiniteTypeImpl(SourceLocation Loc, QualType T, + bool AllowSizeless, TypeDiagnoser *Diagnoser); struct ModuleScope { @@ -1599,14 +1600,33 @@ SourceLocation Loc, const NamedDecl *D, ArrayRef Equiv); + bool isDefiniteType(SourceLocation Loc, QualType T) { + return !RequireDefiniteTypeImpl(Loc, T, true, nullptr); + } + bool isIndefiniteType(SourceLocation Loc, QualType T) { + return !isDefiniteType(Loc, T); + } bool isCompleteType(SourceLocation Loc, QualType T) { - return !RequireCompleteTypeImpl(Loc, T, nullptr); + return !RequireDefiniteTypeImpl(Loc, T, false, nullptr); } - bool RequireCompleteType(SourceLocation Loc, QualType T, + bool RequireDefiniteType(SourceLocation Loc, QualType T, bool AllowSizeless, TypeDiagnoser &Diagnoser); - bool RequireCompleteType(SourceLocation Loc, QualType T, + bool RequireDefiniteType(SourceLocation Loc, QualType T, bool AllowSizeless, unsigned DiagID); - + template + bool RequireDefiniteType(SourceLocation Loc, QualType T, bool AllowSizeless, + unsigned DiagID, const Ts &...Args) { + BoundTypeDiagnoser Diagnoser(DiagID, Args...); + return RequireDefiniteType(Loc, T, AllowSizeless, Diagnoser); + } + bool RequireCompleteType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser) { + return RequireDefiniteType(Loc, T, false, Diagnoser); + } + bool RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID) { + return RequireDefiniteType(Loc, T, false, DiagID); + } template bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -2295,6 +2295,10 @@ StructSize.getValue() == static_cast(getTypeSize(Ty)); } + // Sizeless built-in types have a unique representation. + if (Ty->isSizelessBuiltinType()) + return true; + // FIXME: More cases to handle here (list by rsmith): // vectors (careful about, eg, vector of 3 foo) // _Complex int and friends Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -633,9 +633,11 @@ // Arrays are not modifiable, only their elements are. if (CT->isArrayType()) return Cl::CM_ArrayType; - // Incomplete types are not modifiable. - if (CT->isIncompleteType()) - return Cl::CM_IncompleteType; + // Incomplete types are not modifiable (C11 6.3.2.1/1). The sizeless type + // extension replaces "incomplete" with "indefinite", so that sizeless + // definite types are modifiable lvalues. + if (CT->isIndefiniteType()) + return Cl::CM_IndefiniteType; // Records with any const fields (recursively) are not modifiable. if (const RecordType *R = CT->getAs()) @@ -697,7 +699,7 @@ case Cl::CM_ConstQualifiedField: return MLV_ConstQualifiedField; case Cl::CM_ConstAddrSpace: return MLV_ConstAddrSpace; case Cl::CM_ArrayType: return MLV_ArrayType; - case Cl::CM_IncompleteType: return MLV_IncompleteType; + case Cl::CM_IndefiniteType: return MLV_IndefiniteType; } llvm_unreachable("Unhandled modifiable type"); } Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -1987,10 +1987,11 @@ return !isa(CanonicalType); } -/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) -/// - a type that can describe objects, but which lacks information needed to -/// determine its size. -bool Type::isIncompleteType(NamedDecl **Def) const { +/// isIndefiniteType - Return true if this is an indefinite type - a type that +/// can describe objects, but which lacks information needed to construct +/// them. For sized types, "indefinite" is equivalent to "incomplete" +/// (C99 6.2.5p1). +bool Type::isIndefiniteType(NamedDecl **Def) const { if (Def) *Def = nullptr; @@ -2020,7 +2021,7 @@ // We don't handle variable arrays (they're not allowed in C++) or // dependent-sized arrays (dependent types are never treated as incomplete). return cast(CanonicalType)->getElementType() - ->isIncompleteType(Def); + ->isIndefiniteType(Def); case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; @@ -2048,7 +2049,7 @@ } case ObjCObject: return cast(CanonicalType)->getBaseType() - ->isIncompleteType(Def); + ->isIndefiniteType(Def); case ObjCInterface: { // ObjC interfaces are incomplete if they are @class, not @interface. ObjCInterfaceDecl *Interface @@ -2086,16 +2087,18 @@ } bool QualType::isCXX98PODType(const ASTContext &Context) const { - // The compiler shouldn't query this for incomplete types, but the user might. + // The compiler shouldn't query this for indefinite types, but the user might. // We return false for that case. Except for incomplete arrays of PODs, which // are PODs according to the standard. + // + // Sizeless built-in types (like other built-in types) are POD. if (isNull()) return false; if ((*this)->isIncompleteArrayType()) return Context.getBaseElementType(*this).isCXX98PODType(Context); - if ((*this)->isIncompleteType()) + if ((*this)->isIndefiniteType()) return false; if (hasNonTrivialObjCLifetime()) @@ -2143,9 +2146,10 @@ if ((*this)->isArrayType()) return Context.getBaseElementType(*this).isTrivialType(Context); - // Return false for incomplete types after skipping any incomplete array + // Return false for indefinite types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. - if ((*this)->isIncompleteType()) + // Fall through to the code below for (incomplete) sizeless definite types. + if ((*this)->isIndefiniteType()) return false; if (hasNonTrivialObjCLifetime()) @@ -2161,7 +2165,11 @@ // types. // As an extension, Clang treats vector types as Scalar types. - if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) + // Built-in sizeless types are an extension to the standard and they + // are all trivial. + if (CanonicalType->isScalarType() || + CanonicalType->isSizelessBuiltinType() || + CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs()) { if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { @@ -2197,13 +2205,18 @@ if (CanonicalType->isDependentType()) return false; - // Return false for incomplete types after skipping any incomplete array types + // Return false for indefinite types after skipping any incomplete array types // which are expressly allowed by the standard and thus our API. - if (CanonicalType->isIncompleteType()) + // Fall through to the code below for (incomplete) sizeless definite types. + if (CanonicalType->isIndefiniteType()) return false; - + // As an extension, Clang treats vector types as Scalar types. - if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) + // Built-in sizeless types are an extension to the standard and they + // are all trivially copyable. + if (CanonicalType->isScalarType() || + CanonicalType->isSizelessBuiltinType() || + CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs()) { @@ -2378,13 +2391,19 @@ const Type *BaseTy = ty->getBaseElementTypeUnsafe(); assert(BaseTy && "NULL element type"); - // Return false for incomplete types after skipping any incomplete array + // Return false for indefinite types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. - if (BaseTy->isIncompleteType()) + // Fall through to the code below for (incomplete) sizeless definite types. + if (BaseTy->isIndefiniteType()) return false; // As an extension, Clang treats vector types as Scalar types. - if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + // Built-in sizeless types are an extension to the standard and they + // are all POD. + if (BaseTy->isScalarType() || + BaseTy->isSizelessBuiltinType() || + BaseTy->isVectorType()) + return true; if (const auto *RT = BaseTy->getAs()) { if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { // C++11 [class]p10: Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -10999,9 +10999,12 @@ // function declarator that is part of a function definition of // that function shall not have incomplete type. // + // The sizeless type extension replaces "incomplete" with "indefinite", + // so that (incomplete) sizeless definite types can be passed to functions. + // // This is also C++ [dcl.fct]p6. if (!Param->isInvalidDecl() && - RequireCompleteType(Param->getLocation(), Param->getType(), + RequireDefiniteType(Param->getLocation(), Param->getType(), true, diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); HasInvalidParm = true; Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -4492,8 +4492,9 @@ if (!CodeCompleter) return; - // A complete type is needed to lookup for constructors. - if (!isCompleteType(Loc, Type)) + // A definite type is needed to lookup for constructors. Fall through + // to the handling below for (incomplete) sizeless definite types. + if (!isDefiniteType(Loc, Type)) return; CXXRecordDecl *RD = Type->getAsCXXRecordDecl(); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -1680,7 +1680,7 @@ if (!isa(D) || isa(D) || isa(D)) return false; - // Types of valid local variables should be complete, so this should succeed. + // Types of valid local variables should be definite, so this should succeed. if (const VarDecl *VD = dyn_cast(D)) { // White-list anything with an __attribute__((unused)) type. @@ -1692,9 +1692,9 @@ return false; } - // If we failed to complete the type for some reason, or if the type is - // dependent, don't diagnose the variable. - if (Ty->isIncompleteType() || Ty->isDependentType()) + // If we failed to make the type definite for some reason, or if the type + // is dependent, don't diagnose the variable. + if (Ty->isIndefiniteType() || Ty->isDependentType()) return false; // Look at the element type to ensure that the warning behaviour is @@ -7477,6 +7477,12 @@ return; } + if (!NewVD->hasLocalStorage() && T->isSizelessType()) { + Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T; + NewVD->setInvalidDecl(); + return; + } + if (isVM && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); NewVD->setInvalidDecl(); @@ -9819,7 +9825,9 @@ // But, issue any diagnostic on the first declaration only. if (Previous.empty() && NewFD->isExternC()) { QualType R = NewFD->getReturnType(); - if (R->isIncompleteType() && !R->isVoidType()) + // "Indefinite" rather than "incomplete" because C functions can + // return (incomplete) sizeless definite types. + if (R->isIndefiniteType() && !R->isVoidType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete) << NewFD << R; else if (!R.isPODType(Context) && !R->isVoidType() && @@ -10632,7 +10640,10 @@ QualType BaseDeclType = VDecl->getType(); if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) BaseDeclType = Array->getElementType(); - if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.7.9/3, to allow initialization of + // identifiers with sizeless definite type. + if (RequireDefiniteType(VDecl->getLocation(), BaseDeclType, true, diag::err_typecheck_decl_incomplete_type)) { RealDecl->setInvalidDecl(); return; @@ -11006,9 +11017,11 @@ QualType Ty = VD->getType(); if (Ty->isDependentType()) return; - // Require a complete type. - if (RequireCompleteType(VD->getLocation(), - Context.getBaseElementType(Ty), + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.7.9/3, to allow initialization of + // identifiers with sizeless definite type. + if (RequireDefiniteType(VD->getLocation(), + Context.getBaseElementType(Ty), true, diag::err_typecheck_decl_incomplete_type)) { VD->setInvalidDecl(); return; @@ -11097,9 +11110,13 @@ // Block scope. C99 6.7p7: If an identifier for an object is // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. + // + // In practice this if statement appears to be dead, since no such + // variable would be classified as DeclarationOnly. Logically it + // should include (incomplete) sizeless definite types though. if (!Type->isDependentType() && Var->isLocalVarDecl() && !Var->hasLinkage() && !Var->isInvalidDecl() && - RequireCompleteType(Var->getLocation(), Type, + RequireDefiniteType(Var->getLocation(), Type, true, diag::err_typecheck_decl_incomplete_type)) Var->setInvalidDecl(); @@ -11180,8 +11197,10 @@ return; if (!Var->hasAttr()) { - if (RequireCompleteType(Var->getLocation(), - Context.getBaseElementType(Type), + // The sizeless type extension replaces "complete" with "definite" + // in C11 6.7/7, to allow declarations with sizeless definite type. + if (RequireDefiniteType(Var->getLocation(), + Context.getBaseElementType(Type), true, diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); return; @@ -12511,11 +12530,13 @@ } // The return type of a function definition must be complete - // (C99 6.9.1p3, C++ [dcl.fct]p6). + // (C99 6.9.1p3, C++ [dcl.fct]p6). The sizeless type extension replaces + // "complete object type" with "definite object type", so that functions + // can return sizeless definite types. QualType ResultType = FD->getReturnType(); if (!ResultType->isDependentType() && !ResultType->isVoidType() && !FD->isInvalidDecl() && - RequireCompleteType(FD->getLocation(), ResultType, + RequireDefiniteType(FD->getLocation(), ResultType, true, diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); @@ -14875,7 +14896,7 @@ InvalidDecl = true; } else { NamedDecl *Def; - EltTy->isIncompleteType(&Def); + EltTy->isIndefiniteType(&Def); if (Def && Def->isInvalidDecl()) { Record->setInvalidDecl(); InvalidDecl = true; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -3578,7 +3578,9 @@ if (const auto *ED = dyn_cast(D)) UnderlyingTy = ED->getIntegerType(); } - if (DiagTy->isDependentType() || DiagTy->isIncompleteType()) + // "Indefinite" rather than "incomplete" because we want to raise an + // error for (incomplete) sizeless definite types below. + if (DiagTy->isDependentType() || DiagTy->isIndefiniteType()) return; // C++11 [dcl.align]p5, C11 6.7.5/4: @@ -3586,6 +3588,7 @@ // not specify an alignment that is less strict than the alignment that // would otherwise be required for the entity being declared. AlignedAttr *AlignasAttr = nullptr; + AlignedAttr *LastAlignedAttr = nullptr; unsigned Align = 0; for (auto *I : D->specific_attrs()) { if (I->isAlignmentDependent()) @@ -3593,9 +3596,13 @@ if (I->isAlignas()) AlignasAttr = I; Align = std::max(Align, I->getAlignment(Context)); + LastAlignedAttr = I; } - if (AlignasAttr && Align) { + if (Align && DiagTy->isSizelessType()) { + Diag(LastAlignedAttr->getLocation(), diag::err_attribute_sizeless_type) + << LastAlignedAttr->getSpelling() << DiagTy; + } else if (AlignasAttr && Align) { CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align); CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy); if (NaturalAlign > RequestedAlign) Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -251,7 +251,11 @@ bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { - if (RequireCompleteType(Param->getLocation(), Param->getType(), + // C++ [dcl.fct]/9: "the type of a parameter ... shall not be an + // incomplete class type". The sizeless type extension leaves this + // wording as-is, so that it doesn't apply to sizeless definite types, + // which at present are never class types. + if (RequireDefiniteType(Param->getLocation(), Param->getType(), true, diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); return true; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -760,7 +760,9 @@ /// Incomplete types are considered POD, since this check can be performed /// when we're in an unevaluated context. Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { - if (Ty->isIncompleteType()) { + // "Indefinite" rather than "incomplete" since (incomplete) sizeless definite + // types can be passed to functions. + if (Ty->isIndefiniteType()) { // C++11 [expr.call]p7: // After these conversions, if the argument does not have arithmetic, // enumeration, pointer, pointer to member, or class type, the program @@ -908,8 +910,11 @@ return Comma.get(); } + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/4, so that arguments can + // have sizeless definite type. if (!getLangOpts().CPlusPlus && - RequireCompleteType(E->getExprLoc(), E->getType(), + RequireDefiniteType(E->getExprLoc(), E->getType(), true, diag::err_call_incomplete_argument)) return ExprError(); @@ -1373,8 +1378,11 @@ } else { // C11 6.5.1.1p2 "The type name in a generic association shall specify a // complete object type other than a variably modified type." + // + // The sizeless type extension replaces "complete" with "definite", + // so that _Generic can be used with sizeless definite types. unsigned D = 0; - if (Types[i]->getType()->isIncompleteType()) + if (Types[i]->getType()->isIndefiniteType()) D = diag::err_assoc_type_incomplete; else if (!Types[i]->getType()->isObjectType()) D = diag::err_assoc_type_nonobject; @@ -4832,8 +4840,10 @@ if (ArgIx < Args.size()) { Arg = Args[ArgIx++]; - if (RequireCompleteType(Arg->getLocStart(), - ProtoArgType, + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/4, so that arguments can + // have sizeless definite type. + if (RequireDefiniteType(Arg->getLocStart(), ProtoArgType, true, diag::err_call_incomplete_argument, Arg)) return true; @@ -5588,8 +5598,10 @@ Arg = ArgE.getAs(); } - if (RequireCompleteType(Arg->getLocStart(), - Arg->getType(), + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/4, so that arguments can + // have sizeless definite type. + if (RequireDefiniteType(Arg->getLocStart(), Arg->getType(), true, diag::err_call_incomplete_argument, Arg)) return ExprError(); @@ -5653,7 +5665,10 @@ return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())); } else if (!literalType->isDependentType() && - RequireCompleteType(LParenLoc, literalType, + // The sizeless type extension replaces "complete object type" + // with "definite object type" in C11 6.5.2.5/1, so that compound + // literals can have sizeless definite type. + RequireDefiniteType(LParenLoc, literalType, true, diag::err_typecheck_decl_incomplete_type, SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); @@ -6884,6 +6899,10 @@ /*isIntFirstExpr=*/false)) return LHSTy; + // Allow ?: operations in which both operands have the same sizeless type. + if (LHSTy->isSizelessType() && LHSTy == RHSTy) + return LHSTy; + // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most // likely forgot to take the address of the other expression. @@ -10689,7 +10708,7 @@ case Expr::MLV_ClassTemporary: DiagID = diag::err_typecheck_expression_not_modifiable_lvalue; break; - case Expr::MLV_IncompleteType: + case Expr::MLV_IndefiniteType: case Expr::MLV_IncompleteVoidType: return S.RequireCompleteType(Loc, E->getType(), diag::err_typecheck_incomplete_type_not_modifiable_lvalue, E); @@ -10965,7 +10984,10 @@ if (RHS.isInvalid()) return QualType(); if (!RHS.get()->getType()->isVoidType()) - S.RequireCompleteType(Loc, RHS.get()->getType(), + // The test is for definiteness rather than completeness because + // the sizeless type extension allows (incomplete) sized definite + // types on the rhs of a comma operator. + S.RequireDefiniteType(Loc, RHS.get()->getType(), true, diag::err_incomplete_type); } @@ -13266,7 +13288,11 @@ << OrigExpr->getType() << E->getSourceRange()); if (!TInfo->getType()->isDependentType()) { - if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(), + // The test is for definiteness rather than completeness because the + // sizeless type extensions allows (incomplete) sizeless definite types + // to be passed to functions. + if (RequireDefiniteType(TInfo->getTypeLoc().getBeginLoc(), + TInfo->getType(), true, diag::err_second_parameter_to_va_arg_incomplete, TInfo->getTypeLoc())) return ExprError(); @@ -15339,7 +15365,10 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD) { - if (ReturnType->isVoidType() || !ReturnType->isIncompleteType()) + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/1, so that functions can + // return sizeless definite types. + if (ReturnType->isVoidType() || ReturnType->isDefiniteType()) return false; // If we're inside a decltype's expression, don't check for a valid return @@ -15370,8 +15399,8 @@ << FD->getDeclName(); } } Diagnoser(FD, CE); - - if (RequireCompleteType(Loc, ReturnType, Diagnoser)) + + if (RequireDefiniteType(Loc, ReturnType, true, Diagnoser)) return true; return false; Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -1350,8 +1350,11 @@ // C++17 [expr.type.conv]p2: // If the type is cv void and the initializer is (), the expression is a // prvalue of the specified type that performs no initialization. + // + // The sizeless type extension replaces "complete" with "definite", + // so that sizeless definite types can be zero-initialized using (). if (!Ty->isVoidType() && - RequireCompleteType(TyBeginLoc, ElemTy, + RequireDefiniteType(TyBeginLoc, ElemTy, true, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); @@ -4313,6 +4316,9 @@ // C++1z [meta.unary.prop]: // remove_all_extents_t shall be a complete type or cv void. + // + // The sizeless type extension replaces "complete" with "definite", + // so that it's possible to apply traits to sizeless definite types. case UTT_IsAggregate: case UTT_IsTrivial: case UTT_IsTriviallyCopyable: @@ -4345,8 +4351,8 @@ if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; - return !S.RequireCompleteType( - Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); + return !S.RequireDefiniteType( + Loc, ArgTy, true, diag::err_incomplete_type_used_in_type_trait_expr); } } @@ -4598,7 +4604,11 @@ // C++14 [meta.unary.prop]: // For incomplete types and function types, is_destructible::value is // false. - if (T->isIncompleteType() || T->isFunctionType()) + // + // The sizeless type extension replaces "incomplete" with "indefinite", + // since sizeless definite types can be created with automatic storage + // duration and must therefore be destructible. + if (T->isIndefiniteType() || T->isFunctionType()) return false; // A type that requires destruction (via a non-trivial destructor or ARC @@ -4824,19 +4834,25 @@ // Precondition: T and all types in the parameter pack Args shall be // complete types, (possibly cv-qualified) void, or arrays of // unknown bound. + // + // The sizeless type extension replaces "complete" with "definite", + // so that sizeless definite types can be used with the traits. for (const auto *TSI : Args) { QualType ArgTy = TSI->getType(); if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; - if (S.RequireCompleteType(KWLoc, ArgTy, + if (S.RequireDefiniteType(KWLoc, ArgTy, true, diag::err_incomplete_type_used_in_type_trait_expr)) return false; } // Make sure the first argument is not incomplete nor a function type. + // + // The sizeless type extension replaces "incomplete" with "indefinite", + // so that sizeless definite types can be used with the traits. QualType T = Args[0]->getType(); - if (T->isIncompleteType() || T->isFunctionType()) + if (T->isIndefiniteType() || T->isFunctionType()) return false; // Make sure the first argument is not an abstract type. @@ -4977,8 +4993,11 @@ if (!BaseInterface || !DerivedInterface) return false; - if (Self.RequireCompleteType( - KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) + // The sizeless type extension replaces "complete" with "definite", + // so that sizeless definite types can be used with the traits. + if (Self.RequireDefiniteType( + KeyLoc, RhsT, true, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; return BaseInterface->isSuperClassOf(DerivedInterface); @@ -5046,7 +5065,10 @@ return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. - if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) + // + // The sizeless type extension replaces "complete" with "definite", + // so that functions can return sizeless definite types. + if (!Self.isDefiniteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) return false; // Compute the result of add_rvalue_reference. @@ -5089,12 +5111,15 @@ // // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. + // + // The sizeless type extension replaces "complete" with "definite", + // so that functions can return sizeless definite types. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, LhsT, + Self.RequireDefiniteType(KeyLoc, LhsT, true, diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, RhsT, + Self.RequireDefiniteType(KeyLoc, RhsT, true, diag::err_incomplete_type_used_in_type_trait_expr)) return false; @@ -7243,7 +7268,10 @@ E = Res.get(); if (!E->getType()->isVoidType()) - RequireCompleteType(E->getExprLoc(), E->getType(), + // The test is based on definiteness rather than completeness + // because (incomplete) sized definite types can be used in an + // ignored result. + RequireDefiniteType(E->getExprLoc(), E->getType(), true, diag::err_incomplete_type); return E; } Index: lib/Sema/SemaFixItUtils.cpp =================================================================== --- lib/Sema/SemaFixItUtils.cpp +++ lib/Sema/SemaFixItUtils.cpp @@ -199,6 +199,9 @@ std::string Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const { + if (T->isSizelessBuiltinType() && LangOpts.CPlusPlus) + return std::string(" = ") + T.getAsString() + "()"; + if (T->isScalarType()) { std::string s = getScalarZeroExpressionForType(*T, Loc, *this); if (!s.empty()) Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -1076,14 +1076,18 @@ // Special-case SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK) << IList->getInit(Index)->getSourceRange(); - } else if (!T->isIncompleteType()) { - // Don't complain for incomplete types, since we'll get an error + } else if (!T->isIndefiniteType()) { + // Don't complain for indefinite types, since we'll get an error // elsewhere QualType CurrentObjectType = StructuredList->getType(); int initKind = CurrentObjectType->isArrayType()? 0 : CurrentObjectType->isVectorType()? 1 : - CurrentObjectType->isScalarType()? 2 : + CurrentObjectType->isScalarType() || + // Treat sizeless builtin types as scalars for the purposes of + // this diagnostic, since the rules are the same. Calling them + // out as a special case is unlikely to be helpful. + CurrentObjectType->isSizelessBuiltinType()? 2 : CurrentObjectType->isUnionType()? 3 : 4; @@ -1120,7 +1124,7 @@ // parts. CheckComplexType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); - } else if (DeclType->isScalarType()) { + } else if (DeclType->isScalarType() || DeclType->isSizelessBuiltinType()) { CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { @@ -1252,7 +1256,8 @@ } // Fall through for subaggregate initialization - } else if (ElemType->isScalarType() || ElemType->isAtomicType()) { + } else if (ElemType->isScalarType() || ElemType->isAtomicType() || + ElemType->isSizelessBuiltinType()) { // FIXME: Need to handle atomic aggregate types with implicit init lists. return CheckScalarType(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); @@ -3213,7 +3218,7 @@ case FK_ReferenceBindingToInitList: case FK_InitListBadDestinationType: case FK_DefaultInitOfConst: - case FK_Incomplete: + case FK_Indefinite: case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: case FK_ListInitializationFailed: @@ -3559,8 +3564,10 @@ if (!S.isStdInitializerList(DestType, &E)) return false; + // "Complete" and "definite" are the same here, because + // std::initializer_list is always sized. if (!S.isCompleteType(List->getExprLoc(), E)) { - Sequence.setIncompleteTypeFailure(E); + Sequence.setIndefiniteTypeFailure(E); return true; } @@ -3734,8 +3741,11 @@ ILE ? MultiExprArg(ILE->getInits(), ILE->getNumInits()) : Args; // The type we're constructing needs to be complete. + // + // "Complete" and "definite" are the same here, since we don't yet support + // sizeless structures. if (!S.isCompleteType(Kind.getLocation(), DestType)) { - Sequence.setIncompleteTypeFailure(DestType); + Sequence.setIndefiniteTypeFailure(DestType); return; } @@ -4020,8 +4030,10 @@ } if (DestType->isRecordType() && + // "Complete" and "definite" are the same here, since we don't yet + // support sizeless structures. !S.isCompleteType(InitList->getLocStart(), DestType)) { - Sequence.setIncompleteTypeFailure(DestType); + Sequence.setIndefiniteTypeFailure(DestType); return; } @@ -4257,7 +4269,9 @@ const RecordType *T2RecordType = nullptr; if ((T2RecordType = T2->getAs()) && - S.isCompleteType(Kind.getLocation(), T2)) { + // "Complete" and "definite" are the same here, since we don't yet + // support sizeless structures. + S.isDefiniteType(Kind.getLocation(), T2)) { // The type we're converting from is a class type, enumerate its conversion // functions. CXXRecordDecl *T2RecordDecl = cast(T2RecordType->getDecl()); @@ -5850,7 +5864,11 @@ // proper call to the copy constructor. for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) { ParmVarDecl *Parm = Constructor->getParamDecl(I); - if (S.RequireCompleteType(Loc, Parm->getType(), + // C++ [dcl.fct]/9: "the type of a parameter ... shall not be an + // incomplete class type". The sizeless type extension leaves this + // wording as-is, so that it doesn't apply to sizeless definite types, + // which at present are never class types. + if (S.RequireDefiniteType(Loc, Parm->getType(), true, diag::err_call_incomplete_argument)) break; @@ -6558,10 +6576,13 @@ return E; // C++1z [conv.rval]/1: T shall be a complete type. + // The sizeless type extension replaces "complete" with "definite", + // so that temporaries with sizeless definite type can be created. + // // FIXME: Does this ever matter (can we form a prvalue of incomplete type)? // If so, we should check for a non-abstract class type here too. QualType T = E->getType(); - if (RequireCompleteType(E->getExprLoc(), T, diag::err_incomplete_type)) + if (RequireDefiniteType(E->getExprLoc(), T, true, diag::err_incomplete_type)) return ExprError(); return CreateMaterializeTemporaryExpr(E->getType(), E, false); @@ -7670,8 +7691,12 @@ break; case OR_No_Viable_Function: - if (!S.RequireCompleteType(Kind.getLocation(), - DestType.getNonReferenceType(), + // The condition is "definiteness" rather than "completeness" because + // (incomplete) sizeless definite types are never completed, and so + // completeness itself is not the problem. The usual "not viable" + // diagnostics are better in that case. + if (!S.RequireDefiniteType(Kind.getLocation(), + DestType.getNonReferenceType(), true, diag::err_typecheck_nonviable_condition_incomplete, Args[0]->getType(), Args[0]->getSourceRange())) S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) @@ -7953,9 +7978,9 @@ } break; - case FK_Incomplete: - S.RequireCompleteType(Kind.getLocation(), FailedIncompleteType, - diag::err_init_incomplete_type); + case FK_Indefinite: + S.RequireDefiniteType(Kind.getLocation(), FailedIndefiniteType, + true, diag::err_init_incomplete_type); break; case FK_ListInitializationFailed: { @@ -8118,8 +8143,8 @@ OS << "default initialization of a const variable"; break; - case FK_Incomplete: - OS << "initialization of incomplete type"; + case FK_Indefinite: + OS << "initialization of indefinite type"; break; case FK_ListInitializationFailed: Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -479,8 +479,10 @@ if (!LSI->ReturnType->isDependentType() && !LSI->ReturnType->isVoidType()) { - if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType, - diag::err_lambda_incomplete_result)) { + // The sizeless type extension allows (incomplete) sizeless + // definite types to be returned from functions. + if (RequireDefiniteType(CallOperator->getLocStart(), LSI->ReturnType, + true, diag::err_lambda_incomplete_result)) { // Do nothing. } } Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -11643,8 +11643,7 @@ static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, QualType QTy, bool FullCheck = true) { - NamedDecl *ND; - if (QTy->isIncompleteType(&ND)) { + if (QTy->isIncompleteType()) { SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; return false; } Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -3467,7 +3467,8 @@ Diag(From->getLocStart(), diag::err_typecheck_ambiguous_condition) << From->getType() << ToType << From->getSourceRange(); else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) { - if (!RequireCompleteType(From->getLocStart(), ToType, + // Allow user-defined conversions to (incomplete) sizeless definite types. + if (!RequireDefiniteType(From->getLocStart(), ToType, true, diag::err_typecheck_nonviable_condition_incomplete, From->getType(), From->getSourceRange())) Diag(From->getLocStart(), diag::err_typecheck_nonviable_condition) @@ -4726,9 +4727,13 @@ ImplicitConversionSequence Result; Result.setBad(BadConversionSequence::no_conversion, From, ToType); - // We need a complete type for what follows. Incomplete types can never be + // We need a definite type for what follows. Indefinite types can never be // initialized from init lists. - if (!S.isCompleteType(From->getLocStart(), ToType)) + // + // The condition is "definiteness" rather than "completeness" because the + // sizeless type extension allows list construction of (incomplete) sized + // definite types. + if (!S.isDefiniteType(From->getLocStart(), ToType)) return Result; // Per DR1467: @@ -6946,7 +6951,10 @@ &ConversionRef, VK_RValue); QualType ConversionType = Conversion->getConversionType(); - if (!isCompleteType(From->getLocStart(), ConversionType)) { + // The condition is "definiteness" rather than "completeness" because the + // sizeless type extension allows user-defined conversions to (incomplete) + // sized definite types. + if (!isDefiniteType(From->getLocStart(), ConversionType)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_final_conversion; return; @@ -9628,13 +9636,17 @@ return; } - // Diagnose references or pointers to incomplete types differently, - // since it's far from impossible that the incompleteness triggered + // Diagnose references or pointers to indefinite types differently, + // since it's far from impossible that the indefiniteness triggered // the failure. + // + // The condition is "indefinite" rather than "incomplete" because + // (incomplete) sized definite types are never completed. The diagnostics + // below are a better fit for them. QualType TempFromTy = FromTy.getNonReferenceType(); if (const PointerType *PTy = TempFromTy->getAs()) TempFromTy = PTy->getPointeeType(); - if (TempFromTy->isIncompleteType()) { + if (TempFromTy->isIndefiniteType()) { // Emit the generic diagnostic and, optionally, add the hints to it. S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) << (unsigned) FnKind << FnDesc Index: lib/Sema/SemaPseudoObject.cpp =================================================================== --- lib/Sema/SemaPseudoObject.cpp +++ lib/Sema/SemaPseudoObject.cpp @@ -241,7 +241,7 @@ if (exp->isGLValue()) return true; QualType ty = exp->getType(); - assert(!ty->isIncompleteType()); + assert(ty->isDefiniteType()); assert(!ty->isDependentType()); if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl()) Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -2744,7 +2744,9 @@ QualType VariableType = VD->getType(); - if (VariableType->isIncompleteType()) + // "Indefinite" rather than "incomplete" since ranges can yield (incomplete) + // sizeless definite types. + if (VariableType->isIndefiniteType()) return; const Expr *InitExpr = VD->getInit(); Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -274,10 +274,10 @@ // Accept, even if we emitted an error diagnostic. break; } - case Expr::MLV_IncompleteType: + case Expr::MLV_IndefiniteType: case Expr::MLV_IncompleteVoidType: - if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), - diag::err_dereference_incomplete_type)) + if (RequireDefiniteType(OutputExpr->getLocStart(), Exprs[i]->getType(), + true, diag::err_dereference_incomplete_type)) return StmtError(); LLVM_FALLTHROUGH; default: @@ -286,6 +286,10 @@ << OutputExpr->getSourceRange()); } + // FIXME: should have a mechanism for sizeless types too. + if (OutputExpr->getType()->isSizelessType()) + continue; + unsigned Size = Context.getTypeSize(OutputExpr->getType()); if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), Size)) @@ -373,10 +377,17 @@ continue; if (!Ty->isVoidType() || !Info.allowsMemory()) - if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(), - diag::err_dereference_incomplete_type)) + // The test is for definiteness rather than completeness because + // the sizeless type extension allows sizeless types to be bound + // to register operands. + if (RequireDefiniteType(InputExpr->getLocStart(), Exprs[i]->getType(), + true, diag::err_dereference_incomplete_type)) return StmtError(); + // FIXME: should have a mechanism for sizeless types too. + if (Ty->isSizelessType()) + continue; + unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) @@ -438,6 +449,7 @@ // Now that we have the right indexes go ahead and check. StringLiteral *Literal = Constraints[ConstraintIdx]; const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); + // FIXME: should have a mechanism for sizeless types too. if (Ty->isDependentType() || Ty->isIncompleteType()) continue; @@ -517,6 +529,10 @@ if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. + // FIXME: should have a mechanism for sizeless types too. + if (InTy->isSizelessType() || OutTy->isSizelessType()) + continue; + // Decide if the input and output are in the same domain (integer/ptr or // floating point. enum AsmDomain { @@ -668,6 +684,7 @@ } // Otherwise, it needs to be a complete type. + // FIXME: should have a mechanism for sizeless types too. if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { return ExprError(); } Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -2033,6 +2033,12 @@ SourceRange Brackets, DeclarationName Entity) { SourceLocation Loc = Brackets.getBegin(); + + if (T->isSizelessType()) { + Diag(Loc, diag::err_array_of_sizeless) << T; + return QualType(); + } + if (getLangOpts().CPlusPlus) { // C++ [dcl.array]p1: // T is called the array element type; this type shall not be a reference @@ -7422,26 +7428,30 @@ return RequireCompleteExprType(E, Diagnoser); } -/// @brief Ensure that the type T is a complete type. +/// @brief Ensure that the type T is a definite type. /// -/// This routine checks whether the type @p T is complete in any -/// context where a complete type is required. If @p T is a complete -/// type, returns false. If @p T is a class template specialization, -/// this routine then attempts to perform class template -/// instantiation. If instantiation fails, or if @p T is incomplete -/// and cannot be completed, issues the diagnostic @p diag (giving it -/// the type @p T) and returns true. +/// This routine checks whether the type @p T is definite in any +/// context where a definite type is required. @p AllowSizeless +/// says whether sizeless types are allowed; it is false if +/// completed (i.e. definite and sized) types are required. +/// If @p T meets these conditions, returns false. If @p T is a class +/// template specialization, this routine then attempts to perform class +/// template instantiation. If instantiation fails, or if @p T is +/// indefinite and cannot be made definite, issues the diagnostic @p diag +/// (giving it the type @p T) and returns true. /// /// @param Loc The location in the source that the incomplete type /// diagnostic should refer to. /// /// @param T The type that this routine is examining for completeness. /// +/// @param AllowSizeless Whether to allow sizeless types. +/// /// @returns @c true if @p T is incomplete and a diagnostic was emitted, /// @c false otherwise. -bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, - TypeDiagnoser &Diagnoser) { - if (RequireCompleteTypeImpl(Loc, T, &Diagnoser)) +bool Sema::RequireDefiniteType(SourceLocation Loc, QualType T, + bool AllowSizeless, TypeDiagnoser &Diagnoser) { + if (RequireDefiniteTypeImpl(Loc, T, AllowSizeless, &Diagnoser)) return true; if (const TagType *Tag = T->getAs()) { if (!Tag->getDecl()->isCompleteDefinitionRequired()) { @@ -7566,11 +7576,12 @@ } } -/// \brief The implementation of RequireCompleteType -bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, +/// \brief The implementation of RequireDefiniteType +bool Sema::RequireDefiniteTypeImpl(SourceLocation Loc, QualType T, + bool AllowSizeless, TypeDiagnoser *Diagnoser) { // FIXME: Add this assertion to make sure we always get instantiation points. - // assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType"); + // assert(!Loc.isInvalid() && "Invalid location in RequireDefiniteType"); // FIXME: Add this assertion to help us flush out problems with // checking for dependent types and type-dependent expressions. // @@ -7589,7 +7600,7 @@ } NamedDecl *Def = nullptr; - bool Incomplete = T->isIncompleteType(&Def); + bool Indefinite = T->isIndefiniteType(&Def); // Check that any necessary explicit specializations are visible. For an // enum, we just need the declaration, so don't check this. @@ -7597,7 +7608,8 @@ checkSpecializationVisibility(Loc, Def); // If we have a complete type, we're done. - if (!Incomplete) { + if (!Indefinite && + (AllowSizeless || !T->isSizelessType())) { // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (Def && @@ -7657,8 +7669,9 @@ } // If the external source completed the type, go through the motions // again to ensure we're allowed to use the completed type. - if (!T->isIncompleteType()) - return RequireCompleteTypeImpl(Loc, T, Diagnoser); + if (T->isDefiniteType(&Def) && + (AllowSizeless || !T->isSizelessType())) + return RequireDefiniteTypeImpl(Loc, T, AllowSizeless, Diagnoser); } } @@ -7706,8 +7719,9 @@ // If we instantiated a definition, check that it's usable, even if // instantiation produced an error, so that repeated calls to this // function give consistent answers. - if (!T->isIncompleteType()) - return RequireCompleteTypeImpl(Loc, T, Diagnoser); + if (T->isDefiniteType(&Def) && + (AllowSizeless || !T->isSizelessType())) + return RequireDefiniteTypeImpl(Loc, T, AllowSizeless, Diagnoser); } } @@ -7739,10 +7753,10 @@ return true; } -bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, - unsigned DiagID) { +bool Sema::RequireDefiniteType(SourceLocation Loc, QualType T, + bool AllowSizeless, unsigned DiagID) { BoundTypeDiagnoser<> Diagnoser(DiagID); - return RequireCompleteType(Loc, T, Diagnoser); + return RequireDefiniteType(Loc, T, AllowSizeless, Diagnoser); } /// \brief Get diagnostic %select index for tag kind for @@ -7991,7 +8005,9 @@ // The enum could be incomplete if we're parsing its definition or // recovering from an error. NamedDecl *FwdDecl = nullptr; - if (BaseType->isIncompleteType(&FwdDecl)) { + // "Complete" and "definite" are the same here, since enums are + // never sizeless. + if (BaseType->isIndefiniteType(&FwdDecl)) { Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; return QualType(); Index: test/Sema/sizeless-1.c =================================================================== --- /dev/null +++ test/Sema/sizeless-1.c @@ -0,0 +1,246 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -Wno-comment -triple arm64-linux-gnu -target-feature +sve -std=c90 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=gnu90 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=c99 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=gnu99 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=c11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=gnu11 %s + +typedef __SVInt8_t svint8_t; +typedef __SVInt16_t svint16_t; + +svint8_t global_int8; // expected-error {{non-local variable with sizeless type}} +extern svint8_t extern_int8; // expected-error {{non-local variable with sizeless type}} +static svint8_t static_int8; // expected-error {{non-local variable with sizeless type}} + +typedef svint8_t int8_typedef; +typedef svint8_t *int8_ptr_typedef; + +int sizeof_int8 = sizeof(svint8_t); // expected-error {{incomplete type}} + +int alignof_int8 = _Alignof(svint8_t); // expected-error {{incomplete type}} + +void pass_int8(svint8_t); // expected-note {{passing argument to parameter here}} + +svint8_t return_int8(); + +typedef svint8_t vec_int8 __attribute__((vector_size(64))); // expected-error {{invalid vector element type}} + +void dump(const volatile void *); + +void __attribute__((overloadable)) overf(svint8_t); +void __attribute__((overloadable)) overf(svint16_t); + +void __attribute__((overloadable)) overf8(svint8_t); // expected-note + {{not viable}} +void __attribute__((overloadable)) overf8(int); // expected-note + {{not viable}} + +void __attribute__((overloadable)) overf16(svint16_t); // expected-note + {{not viable}} +void __attribute__((overloadable)) overf16(int); // expected-note + {{not viable}} + +void varargs(int, ...); + +void unused() { + svint8_t unused_int8; // expected-warning {{unused}} +} + +void func(int sel) { + svint8_t local_int8; + svint16_t local_int16; + + svint8_t __attribute__((aligned)) aligned_int8_1; // expected-error {{sizeless type}} + svint8_t __attribute__((aligned(4))) aligned_int8_2; // expected-error {{sizeless type}} + svint8_t _Alignas(int) aligned_int8_3; // expected-error {{sizeless type}} + int _Alignas(svint8_t) aligned_int; // expected-error {{incomplete type}} + + local_int8; // expected-warning {{expression result unused}} + + (void)local_int8; + + local_int8, 0; // expected-warning + {{expression result unused}} + + 0, local_int8; // expected-warning + {{expression result unused}} + + svint8_t init_int8 = local_int8; + + int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}} + svint8_t empty_brace_init_int8 = {}; // expected-error {{scalar initializer cannot be empty}} + svint8_t brace_init_int8 = { local_int8 }; + svint8_t bad_brace_init_int8 = { local_int8, 0 }; // expected-warning {{excess elements in scalar initializer}} + + const svint8_t const_int8 = local_int8; // expected-note {{declared const here}} + + const svint8_t uninit_const_int8; + + volatile svint8_t volatile_int8; + + const volatile svint8_t const_volatile_int8; // expected-note {{declared const here}} + + _Atomic svint8_t atomic_int8; // expected-error {{_Atomic cannot be applied to incomplete type}} + __restrict svint8_t restrict_int8; // expected-error {{requires a pointer or reference}} + + svint8_t array_int8[1]; // expected-error {{array has sizeless element type}} + + _Bool test_int8 = init_int8; // expected-error {{incompatible type}} + + int int_int8 = init_int8; // expected-error {{incompatible type}} + + init_int8 = local_int8; + init_int8 = local_int16; // expected-error {{incompatible type}} + init_int8 = sel; // expected-error {{incompatible type}} + + sel = local_int8; // expected-error {{incompatible type}} + + local_int8 = (svint8_t)local_int8; // expected-error {{cast to incomplete type}} + local_int8 = (const svint8_t)local_int8; // expected-error {{cast to incomplete type}} + local_int8 = (svint8_t)local_int8; // expected-error {{cast to incomplete type}} + + init_int8 = local_int8; + init_int8 = const_int8; + init_int8 = volatile_int8; + init_int8 = const_volatile_int8; + + const_int8 = local_int8; // expected-error {{const-qualified type}} + + volatile_int8 = local_int8; + volatile_int8 = const_int8; + volatile_int8 = volatile_int8; + volatile_int8 = const_volatile_int8; + + const_volatile_int8 = local_int8; // expected-error {{const-qualified type}} + + init_int8 = sel ? init_int8 : local_int8; + init_int8 = sel ? init_int8 : const_int8; + init_int8 = sel ? volatile_int8 : const_int8; + init_int8 = sel ? volatile_int8 : const_volatile_int8; + + pass_int8(local_int8); + pass_int8(local_int16); // expected-error {{incompatible type}} + + local_int8 = return_int8(); + local_int16 = return_int8(); // expected-error {{incompatible type}} + + dump(&local_int8); + dump(&const_int8); + dump(&volatile_int8); + dump(&const_volatile_int8); + + dump(&local_int8 + 1); // expected-error {{arithmetic on a pointer to an incomplete type}} + + *&local_int8 = local_int8; + *&const_int8 = local_int8; // expected-error {{read-only variable}} + *&volatile_int8 = local_int8; + *&const_volatile_int8 = local_int8; // expected-error {{read-only variable}} + + overf(local_int8); + overf(local_int16); + + overf8(local_int8); + overf8(local_int16); // expected-error {{no matching function}} + + overf16(local_int8); // expected-error {{no matching function}} + overf16(local_int16); + + varargs(1, local_int8, local_int16); + + +init_int8; // expected-error {{invalid argument type}} + ++init_int8; // expected-error {{cannot increment}} + -init_int8; // expected-error {{invalid argument type}} + --init_int8; // expected-error {{cannot decrement}} + ~init_int8; // expected-error {{invalid argument type}} + !init_int8; // expected-error {{invalid argument type}} + *init_int8; // expected-error {{requires pointer operand}} + __real init_int8; // expected-error {{invalid type}} + __imag init_int8; // expected-error {{invalid type}} + + local_int8 + init_int8; // expected-error {{invalid operands}} + local_int8 - init_int8; // expected-error {{invalid operands}} + local_int8 * init_int8; // expected-error {{invalid operands}} + local_int8 / init_int8; // expected-error {{invalid operands}} + local_int8 % init_int8; // expected-error {{invalid operands}} + local_int8 & init_int8; // expected-error {{invalid operands}} + local_int8 | init_int8; // expected-error {{invalid operands}} + local_int8 ^ init_int8; // expected-error {{invalid operands}} + local_int8 << init_int8; // expected-error {{invalid operands}} + local_int8 >> init_int8; // expected-error {{invalid operands}} + local_int8 < init_int8; // expected-error {{invalid operands}} + local_int8 <= init_int8; // expected-error {{invalid operands}} + local_int8 == init_int8; // expected-error {{invalid operands}} + local_int8 != init_int8; // expected-error {{invalid operands}} + local_int8 >= init_int8; // expected-error {{invalid operands}} + local_int8 > init_int8; // expected-error {{invalid operands}} + local_int8 && init_int8; // expected-error {{invalid operands}} + local_int8 || init_int8; // expected-error {{invalid operands}} + + local_int8 += init_int8; // expected-error {{invalid operands}} + local_int8 -= init_int8; // expected-error {{invalid operands}} + local_int8 *= init_int8; // expected-error {{invalid operands}} + local_int8 /= init_int8; // expected-error {{invalid operands}} + local_int8 %= init_int8; // expected-error {{invalid operands}} + local_int8 &= init_int8; // expected-error {{invalid operands}} + local_int8 |= init_int8; // expected-error {{invalid operands}} + local_int8 ^= init_int8; // expected-error {{invalid operands}} + local_int8 <<= init_int8; // expected-error {{invalid operands}} + local_int8 >>= init_int8; // expected-error {{invalid operands}} + + local_int8 + 0; // expected-error {{invalid operands}} + local_int8 - 0; // expected-error {{invalid operands}} + local_int8 * 0; // expected-error {{invalid operands}} + local_int8 / 0; // expected-error {{invalid operands}} + local_int8 % 0; // expected-error {{invalid operands}} + local_int8 & 0; // expected-error {{invalid operands}} + local_int8 | 0; // expected-error {{invalid operands}} + local_int8 ^ 0; // expected-error {{invalid operands}} + local_int8 << 0; // expected-error {{invalid operands}} + local_int8 >> 0; // expected-error {{invalid operands}} + local_int8 < 0; // expected-error {{invalid operands}} + local_int8 <= 0; // expected-error {{invalid operands}} + local_int8 == 0; // expected-error {{invalid operands}} + local_int8 != 0; // expected-error {{invalid operands}} + local_int8 >= 0; // expected-error {{invalid operands}} + local_int8 > 0; // expected-error {{invalid operands}} + local_int8 && 0; // expected-error {{invalid operands}} + local_int8 || 0; // expected-error {{invalid operands}} + + if (local_int8) {} // expected-error {{statement requires expression of scalar type}} + while (local_int8) {} // expected-error {{statement requires expression of scalar type}} + do {} while (local_int8); // expected-error {{statement requires expression of scalar type}} + switch (local_int8) { default:; } // expected-error {{integer type}} +} + +int vararg_receiver(int count, svint8_t first, ...) { + __builtin_va_list va; + + __builtin_va_start(va, first); + __builtin_va_arg(va, svint8_t); + __builtin_va_end(va); + return count; +} + +struct sized_struct { + int f1; + svint8_t f2; // expected-error {{field has incomplete type}} + svint8_t f3 : 2; // expected-error {{incomplete type}} +}; + +union sized_union { + int f1; + svint8_t f2; // expected-error {{field has incomplete type}} + svint8_t f3 : 2; // expected-error {{incomplete type}} +}; + +#if __STDC_VERSION__ >= 201112L +void test_generic(void) { + svint8_t local_int8; + svint16_t local_int16; + + int a1[_Generic (local_int8, svint8_t: 1, svint16_t: 2, default: 3) == 1 ? 1 : -1]; + int a2[_Generic (local_int16, svint8_t: 1, svint16_t: 2, default: 3) == 2 ? 1 : -1]; + int a3[_Generic (0, svint8_t: 1, svint16_t: 2, default: 3) == 3 ? 1 : -1]; + (void)_Generic (0, svint8_t: 1, svint8_t: 2, default: 3); // expected-error {{compatible with previously specified}} expected-note {{compatible type}} +} + +void test_compound_literal(void) { + svint8_t local_int8; + + (void) (svint8_t) { local_int8 }; +} +#endif Index: test/SemaCXX/sizeless-1.cpp =================================================================== --- /dev/null +++ test/SemaCXX/sizeless-1.cpp @@ -0,0 +1,479 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++98 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++98 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++11 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++11 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++14 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++14 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++17 %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++17 %s + +typedef __SVInt8_t svint8_t; +typedef __SVInt16_t svint16_t; + +svint8_t global_int8; // expected-error {{non-local variable with sizeless type}} +extern svint8_t extern_int8; // expected-error {{non-local variable with sizeless type}} +static svint8_t static_int8; // expected-error {{non-local variable with sizeless type}} + +typedef svint8_t int8_typedef; +typedef svint8_t *int8_ptr_typedef; + +int sizeof_int8 = sizeof(svint8_t); // expected-error {{incomplete type}} + +int alignof_int8 = _Alignof(svint8_t); // expected-error {{incomplete type}} + +void pass_int8(svint8_t); // expected-note {{no known conversion}} + +extern "C" svint8_t return_int8(); + +typedef svint8_t vec_int8 __attribute__((vector_size(64))); // expected-error {{invalid vector element type}} + +void dump(const volatile void *); + +void overf(svint8_t); +void overf(svint16_t); + +void overf8(svint8_t); // expected-note + {{not viable}} +void overf8(int); // expected-note + {{not viable}} + +void overf16(svint16_t); // expected-note + {{not viable}} +void overf16(int); // expected-note + {{not viable}} + +void varargs(int, ...); + +void unused() { + svint8_t unused_int8; // expected-warning {{unused}} +} + +void func(int sel) { + svint8_t local_int8; + svint16_t local_int16; + + svint8_t __attribute__((aligned)) aligned_int8_1; // expected-error {{sizeless type}} + svint8_t __attribute__((aligned(4))) aligned_int8_2; // expected-error {{sizeless type}} + svint8_t _Alignas(int) aligned_int8_3; // expected-error {{sizeless type}} + int _Alignas(svint8_t) aligned_int; // expected-error {{incomplete type}} + + (void)__atomic_is_lock_free(1, &local_int8); + (void)__atomic_always_lock_free(1, &local_int8); + + local_int8; // expected-warning {{expression result unused}} + + (void)local_int8; + + local_int8, 0; // expected-warning + {{expression result unused}} + + 0, local_int8; // expected-warning + {{expression result unused}} + + svint8_t init_int8 = local_int8; + +#if __cplusplus >= 201103L + int empty_brace_init_int = {}; + svint8_t empty_brace_init_int8 = {}; +#else + int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}} + svint8_t empty_brace_init_int8 = {}; // expected-error {{scalar initializer cannot be empty}} +#endif + svint8_t brace_init_int8 = { local_int8 }; + svint8_t bad_brace_init_int8 = { local_int8, 0 }; // expected-error {{excess elements in scalar initializer}} + + const svint8_t const_int8 = local_int8; // expected-note {{declared const here}} + + const svint8_t uninit_const_int8; // expected-error {{default initialization}} + + volatile svint8_t volatile_int8; + + const volatile svint8_t const_volatile_int8; // expected-error {{default initialization}} expected-note {{declared const here}} + + _Atomic svint8_t atomic_int8; // expected-error {{_Atomic cannot be applied to incomplete type}} + __restrict svint8_t restrict_int8; // expected-error {{requires a pointer or reference}} + + svint8_t array_int8[1]; // expected-error {{array has sizeless element type}} + + bool test_int8 = init_int8; // expected-error {{cannot initialize}} + + int int_int8 = init_int8; // expected-error {{cannot initialize}} + + init_int8 = local_int8; + init_int8 = local_int16; // expected-error {{incompatible type}} + init_int8 = sel; // expected-error {{incompatible type}} + + sel = local_int8; // expected-error {{incompatible type}} + + local_int8 = (svint8_t)local_int8; + local_int8 = (const svint8_t)local_int8; + local_int8 = (svint8_t)local_int16; // expected-error {{not allowed}} + + init_int8 = local_int8; + init_int8 = const_int8; + init_int8 = volatile_int8; + init_int8 = const_volatile_int8; + + const_int8 = local_int8; // expected-error {{const-qualified type}} + + volatile_int8 = local_int8; + volatile_int8 = const_int8; + volatile_int8 = volatile_int8; + volatile_int8 = const_volatile_int8; + + const_volatile_int8 = local_int8; // expected-error {{const-qualified type}} + + init_int8 = sel ? init_int8 : local_int8; + init_int8 = sel ? init_int8 : const_int8; + init_int8 = sel ? volatile_int8 : const_int8; + init_int8 = sel ? volatile_int8 : const_volatile_int8; + + pass_int8(local_int8); + pass_int8(local_int16); // expected-error {{no matching function}} + + local_int8 = return_int8(); + local_int16 = return_int8(); // expected-error {{incompatible type}} + + dump(&local_int8); + dump(&const_int8); + dump(&volatile_int8); + dump(&const_volatile_int8); + + dump(&local_int8 + 1); // expected-error {{arithmetic on a pointer to an incomplete type}} + + *&local_int8 = local_int8; + *&const_int8 = local_int8; // expected-error {{read-only variable}} + *&volatile_int8 = local_int8; + *&const_volatile_int8 = local_int8; // expected-error {{read-only variable}} + + (&local_int8)[0] = local_int8; // expected-error {{subscript of pointer to incomplete type}} + + overf(local_int8); + overf(local_int16); + + overf8(local_int8); + overf8(local_int16); // expected-error {{no matching function}} + + overf16(local_int8); // expected-error {{no matching function}} + overf16(local_int16); + + varargs(1, local_int8, local_int16); + + +init_int8; // expected-error {{invalid argument type}} + ++init_int8; // expected-error {{cannot increment}} + -init_int8; // expected-error {{invalid argument type}} + --init_int8; // expected-error {{cannot decrement}} + ~init_int8; // expected-error {{invalid argument type}} + !init_int8; // expected-error {{invalid argument type}} + *init_int8; // expected-error {{requires pointer operand}} + __real init_int8; // expected-error {{invalid type}} + __imag init_int8; // expected-error {{invalid type}} + + local_int8 + init_int8; // expected-error {{invalid operands}} + local_int8 - init_int8; // expected-error {{invalid operands}} + local_int8 * init_int8; // expected-error {{invalid operands}} + local_int8 / init_int8; // expected-error {{invalid operands}} + local_int8 % init_int8; // expected-error {{invalid operands}} + local_int8 & init_int8; // expected-error {{invalid operands}} + local_int8 | init_int8; // expected-error {{invalid operands}} + local_int8 ^ init_int8; // expected-error {{invalid operands}} + local_int8 << init_int8; // expected-error {{invalid operands}} + local_int8 >> init_int8; // expected-error {{invalid operands}} + local_int8 < init_int8; // expected-error {{invalid operands}} + local_int8 <= init_int8; // expected-error {{invalid operands}} + local_int8 == init_int8; // expected-error {{invalid operands}} + local_int8 != init_int8; // expected-error {{invalid operands}} + local_int8 >= init_int8; // expected-error {{invalid operands}} + local_int8 > init_int8; // expected-error {{invalid operands}} + local_int8 && init_int8; // expected-error {{invalid operands}} expected-error {{not contextually convertible}} + local_int8 || init_int8; // expected-error {{invalid operands}} expected-error {{not contextually convertible}} + + local_int8 += init_int8; // expected-error {{invalid operands}} + local_int8 -= init_int8; // expected-error {{invalid operands}} + local_int8 *= init_int8; // expected-error {{invalid operands}} + local_int8 /= init_int8; // expected-error {{invalid operands}} + local_int8 %= init_int8; // expected-error {{invalid operands}} + local_int8 &= init_int8; // expected-error {{invalid operands}} + local_int8 |= init_int8; // expected-error {{invalid operands}} + local_int8 ^= init_int8; // expected-error {{invalid operands}} + local_int8 <<= init_int8; // expected-error {{invalid operands}} + local_int8 >>= init_int8; // expected-error {{invalid operands}} + + local_int8 + 0; // expected-error {{invalid operands}} + local_int8 - 0; // expected-error {{invalid operands}} + local_int8 * 0; // expected-error {{invalid operands}} + local_int8 / 0; // expected-error {{invalid operands}} + local_int8 % 0; // expected-error {{invalid operands}} + local_int8 & 0; // expected-error {{invalid operands}} + local_int8 | 0; // expected-error {{invalid operands}} + local_int8 ^ 0; // expected-error {{invalid operands}} + local_int8 << 0; // expected-error {{invalid operands}} + local_int8 >> 0; // expected-error {{invalid operands}} + local_int8 < 0; // expected-error {{invalid operands}} + local_int8 <= 0; // expected-error {{invalid operands}} + local_int8 == 0; // expected-error {{invalid operands}} + local_int8 != 0; // expected-error {{invalid operands}} + local_int8 >= 0; // expected-error {{invalid operands}} + local_int8 > 0; // expected-error {{invalid operands}} + local_int8 && 0; // expected-error {{invalid operands}} expected-error {{not contextually convertible}} + local_int8 || 0; // expected-error {{invalid operands}} expected-error {{not contextually convertible}} + + if (local_int8) {} // expected-error {{not contextually convertible}} + while (local_int8) {} // expected-error {{not contextually convertible}} + do {} while (local_int8); // expected-error {{not contextually convertible}} + switch (local_int8) { default:; } // expected-error {{integer type}} +} + +int vararg_receiver(int count, svint8_t first, ...) { + __builtin_va_list va; + + __builtin_va_start(va, first); + __builtin_va_arg(va, svint8_t); + __builtin_va_end(va); + return count; +} + +struct sized_struct { + int f1; + svint8_t f2; // expected-error {{field has incomplete type}} + svint8_t f3 : 2; // expected-error {{incomplete type}} +}; + +union sized_union { + int f1; + svint8_t f2; // expected-error {{field has incomplete type}} + svint8_t f3 : 2; // expected-error {{incomplete type}} +}; + +void pass_int8_ref(svint8_t &); // expected-note {{not viable}} + +svint8_t &return_int8_ref(); +#if __cplusplus >= 201103L +svint8_t &&return_int8_rvalue_ref(); +#endif + +template struct s_template { + T y; // expected-error {{incomplete type}} +}; + +template struct s_ptr_template { + s_ptr_template(); + s_ptr_template(T, svint8_t = svint8_t()); + s_ptr_template(const s_ptr_template &, svint8_t = svint8_t()); + T *y; +}; + +template struct s_array_template { + T y[1]; // expected-error {{array has sizeless element type}} +}; + +struct widget { + widget(s_ptr_template); + svint8_t operator[](int); +}; + +struct foo_iterator { + svint8_t operator++(); + svint8_t operator*() const; + bool operator!=(const foo_iterator &) const; +}; + +struct foo { + foo(); + operator svint8_t() const; + foo_iterator begin() const; + foo_iterator end() const; +}; + +struct constructible_from_sizeless { + constructible_from_sizeless(svint8_t); +}; + +void with_default(svint8_t = svint8_t()); + +#if __cplusplus < 201703L +void throwing_func() throw(svint8_t); // expected-error {{incomplete type}} +void throwing_pointer_func() throw(svint8_t *); // expected-error {{pointer to incomplete type}} +void throwing_pointer_func() throw(svint8_t &); // expected-error {{reference to incomplete type}} +#endif + +template void template_fn_direct(T) {} +template void template_fn_ref(T &) {} +template void template_fn_const_ref(const T &) {} +#if __cplusplus >= 201103L +template void template_fn_rvalue_ref(T &&) {} +#endif + +void cxx_only() { + svint8_t local_int8; + svint16_t local_int16; + + pass_int8_ref(local_int8); + pass_int8_ref(local_int16); // expected-error {{no matching function}} + + local_int8 = return_int8_ref(); + local_int16 = return_int8_ref(); // expected-error {{incompatible type}} + return_int8_ref() = local_int8; + return_int8_ref() = local_int16; // expected-error {{incompatible type}} + +#if __cplusplus >= 201103L + local_int8 = return_int8_rvalue_ref(); + local_int16 = return_int8_rvalue_ref(); // expected-error {{incompatible type}} + + return_int8_rvalue_ref() = local_int8; // expected-error {{not assignable}} + return_int8_rvalue_ref() = local_int16; // expected-error {{not assignable}} +#endif + + local_int8 = static_cast(local_int8); + local_int8 = static_cast(local_int16); // expected-error {{not allowed}} + local_int16 = static_cast(local_int8); // expected-error {{not allowed}} + + throw 1; + throw local_int8; // expected-error {{cannot throw object of incomplete type}} + + try {} catch (int) {} + try {} catch (svint8_t) {} // expected-error {{cannot catch incomplete type}} + try {} catch (svint8_t *) {} // expected-error {{cannot catch pointer to incomplete type}} + try {} catch (svint8_t &) {} // expected-error {{cannot catch reference to incomplete type}} + + new svint8_t; // expected-error {{allocation of incomplete type}} + new svint8_t(); // expected-error {{allocation of incomplete type}} + + (void)svint8_t(); + + local_int8 = svint8_t(); + local_int8 = svint16_t(); // expected-error {{incompatible type}} + + s_template st_int; + s_template st_svint8; // expected-note {{in instantiation}} + + s_ptr_template st_ptr_int; + s_ptr_template st_ptr_svint8; + + widget w(1); + local_int8 = w[1]; + + s_array_template st_array_int; + s_array_template st_array_svint8; // expected-note {{in instantiation}} + + local_int8 = static_cast(foo()); + local_int16 = static_cast(foo()); // expected-error {{incompatible type}} + + local_int8 = foo(); + local_int16 = foo(); // expected-error {{incompatible type}} + + svint8_t &ref_int8 = local_int8; + ref_int8 = ref_int8; // expected-warning {{to itself}} + ref_int8 = local_int8; + local_int8 = ref_int8; + +#if __cplusplus >= 201103L + svint8_t zero_init_int8 {}; + svint8_t init_int8 { local_int8 }; +#endif + + template_fn_direct(local_int8); + template_fn_ref(local_int8); + template_fn_const_ref(local_int8); +#if __cplusplus >= 201103L + template_fn_rvalue_ref(local_int8); +#endif + + _Static_assert(__is_trivially_destructible(svint8_t), ""); + _Static_assert(!__is_nothrow_assignable(svint8_t, svint8_t), ""); + _Static_assert(__is_nothrow_assignable(svint8_t &, svint8_t), ""); + _Static_assert(!__is_nothrow_assignable(svint8_t &, svint16_t), ""); + _Static_assert(__is_constructible(svint8_t), ""); + _Static_assert(__is_constructible(svint8_t, svint8_t), ""); + _Static_assert(!__is_constructible(svint8_t, svint8_t, svint8_t), ""); + _Static_assert(!__is_constructible(svint8_t, svint16_t), ""); + _Static_assert(__is_nothrow_constructible(svint8_t), ""); + _Static_assert(__is_nothrow_constructible(svint8_t, svint8_t), ""); + _Static_assert(!__is_nothrow_constructible(svint8_t, svint16_t), ""); + _Static_assert(!__is_assignable(svint8_t, svint8_t), ""); + _Static_assert(__is_assignable(svint8_t &, svint8_t), ""); + _Static_assert(!__is_assignable(svint8_t &, svint16_t), ""); + _Static_assert(__has_nothrow_assign(svint8_t), ""); + _Static_assert(__has_nothrow_move_assign(svint8_t), ""); + _Static_assert(__has_nothrow_copy(svint8_t), ""); + _Static_assert(__has_nothrow_constructor(svint8_t), ""); + _Static_assert(__has_trivial_assign(svint8_t), ""); + _Static_assert(__has_trivial_move_assign(svint8_t), ""); + _Static_assert(__has_trivial_copy(svint8_t), ""); + _Static_assert(__has_trivial_constructor(svint8_t), ""); + _Static_assert(__has_trivial_move_constructor(svint8_t), ""); + _Static_assert(__has_trivial_destructor(svint8_t), ""); + _Static_assert(!__has_virtual_destructor(svint8_t), ""); + _Static_assert(!__is_abstract(svint8_t), ""); + _Static_assert(!__is_aggregate(svint8_t), ""); + _Static_assert(!__is_base_of(svint8_t, svint8_t), ""); + _Static_assert(!__is_class(svint8_t), ""); + _Static_assert(__is_convertible_to(svint8_t, svint8_t), ""); + _Static_assert(!__is_convertible_to(svint8_t, svint16_t), ""); + _Static_assert(!__is_empty(svint8_t), ""); + _Static_assert(!__is_enum(svint8_t), ""); + _Static_assert(!__is_final(svint8_t), ""); + _Static_assert(!__is_literal(svint8_t), ""); + _Static_assert(__is_pod(svint8_t), ""); + _Static_assert(!__is_polymorphic(svint8_t), ""); + _Static_assert(__is_trivial(svint8_t), ""); + _Static_assert(__is_object(svint8_t), ""); + _Static_assert(__has_unique_object_representations(svint8_t), ""); + _Static_assert(!__is_arithmetic(svint8_t), ""); + _Static_assert(!__is_floating_point(svint8_t), ""); + _Static_assert(!__is_integral(svint8_t), ""); + _Static_assert(!__is_complete_type(svint8_t), ""); + _Static_assert(!__is_void(svint8_t), ""); + _Static_assert(!__is_array(svint8_t), ""); + _Static_assert(!__is_function(svint8_t), ""); + _Static_assert(!__is_reference(svint8_t), ""); + _Static_assert(__is_reference(svint8_t &), ""); + _Static_assert(__is_reference(const svint8_t &), ""); + _Static_assert(!__is_lvalue_reference(svint8_t), ""); + _Static_assert(__is_lvalue_reference(svint8_t &), ""); +#if __cplusplus >= 201103L + _Static_assert(!__is_lvalue_reference(svint8_t &&), ""); +#endif + _Static_assert(!__is_rvalue_reference(svint8_t), ""); + _Static_assert(!__is_rvalue_reference(svint8_t &), ""); +#if __cplusplus >= 201103L + _Static_assert(__is_rvalue_reference(svint8_t &&), ""); +#endif + _Static_assert(!__is_fundamental(svint8_t), ""); + _Static_assert(__is_object(svint8_t), ""); + _Static_assert(!__is_scalar(svint8_t), ""); + _Static_assert(!__is_compound(svint8_t), ""); + _Static_assert(!__is_pointer(svint8_t), ""); + _Static_assert(__is_pointer(svint8_t *), ""); + _Static_assert(!__is_member_object_pointer(svint8_t), ""); + _Static_assert(!__is_member_function_pointer(svint8_t), ""); + _Static_assert(!__is_member_pointer(svint8_t), ""); + _Static_assert(!__is_const(svint8_t), ""); + _Static_assert(__is_const(const svint8_t), ""); + _Static_assert(__is_const(const volatile svint8_t), ""); + _Static_assert(!__is_volatile(svint8_t), ""); + _Static_assert(__is_volatile(volatile svint8_t), ""); + _Static_assert(__is_volatile(const volatile svint8_t), ""); + _Static_assert(!__is_standard_layout(svint8_t), ""); + // At present these types are opaque and don't have the properties + // implied by their name. + _Static_assert(!__is_signed(svint8_t), ""); + _Static_assert(!__is_unsigned(svint8_t), ""); + +#if __cplusplus >= 201103L + auto auto_int8 = local_int8; + auto auto_int16 = local_int16; +#if __cplusplus >= 201703L + auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose}} +#endif +#endif + + s_ptr_template y; + s_ptr_template &x = y; + + constructible_from_sizeless cfs1(local_int8); + constructible_from_sizeless cfs2 = local_int8; +#if __cplusplus >= 201103L + constructible_from_sizeless cfs3 { local_int8 }; +#endif + +#if __cplusplus >= 201103L + for (auto x : local_int8) {} // expected-error {{incomplete type}} + + for (const svint8_t &x : foo()) { (void)x; } // expected-warning {{always a copy}} expected-note {{use non-reference type}} +#endif +}