diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1788,11 +1788,7 @@ /// Relax the normal rules for complete types so that they include /// sizeless built-in types. - AcceptSizeless, - - // FIXME: Eventually we should flip the default to Normal and opt in - // to AcceptSizeless rather than opt out of it. - Default = AcceptSizeless + AcceptSizeless }; private: @@ -1900,7 +1896,7 @@ bool isUsualDeallocationFunction(const CXXMethodDecl *FD); bool isCompleteType(SourceLocation Loc, QualType T, - CompleteTypeKind Kind = CompleteTypeKind::Default) { + CompleteTypeKind Kind = CompleteTypeKind::Normal) { return !RequireCompleteTypeImpl(Loc, T, Kind, nullptr); } bool RequireCompleteType(SourceLocation Loc, QualType T, @@ -1910,10 +1906,10 @@ bool RequireCompleteType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser) { - return RequireCompleteType(Loc, T, CompleteTypeKind::Default, Diagnoser); + return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser); } bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID) { - return RequireCompleteType(Loc, T, CompleteTypeKind::Default, DiagID); + return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, DiagID); } template @@ -1922,6 +1918,13 @@ BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteType(Loc, T, Diagnoser); } + template + bool RequireCompleteType(SourceLocation Loc, QualType T, + CompleteTypeKind Kind, unsigned DiagID, + const Ts &... Args) { + BoundTypeDiagnoser Diagnoser(DiagID, Args...); + return RequireCompleteType(Loc, T, Kind, Diagnoser); + } template bool RequireCompleteSizedType(SourceLocation Loc, QualType T, unsigned DiagID, @@ -1935,10 +1938,16 @@ TypeDiagnoser &Diagnoser); bool RequireCompleteExprType(Expr *E, unsigned DiagID); + template + bool RequireCompleteExprType(Expr *E, CompleteTypeKind Kind, unsigned DiagID, + const Ts &... Args) { + BoundTypeDiagnoser Diagnoser(DiagID, Args...); + return RequireCompleteExprType(E, Kind, Diagnoser); + } template bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); - return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser); + return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser); } template diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2646,7 +2646,10 @@ if (SrcExpr.isInvalid()) return; + // Being sizeless doesn't in itself prevent casting, so diagnose invalid + // cases below instead. if (Self.RequireCompleteType(OpRange.getBegin(), DestType, + Sema::CompleteTypeKind::AcceptSizeless, diag::err_typecheck_cast_to_incomplete)) { SrcExpr = ExprError(); return; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -12848,6 +12848,8 @@ // This is also C++ [dcl.fct]p6. if (!Param->isInvalidDecl() && RequireCompleteType(Param->getLocation(), Param->getType(), + // Function parameters can have sizeless type. + CompleteTypeKind::AcceptSizeless, diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); HasInvalidParm = true; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11854,6 +11854,9 @@ if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) BaseDeclType = Array->getElementType(); if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, + // Local variables can have sizeless type. + // We diagnose invalid sizeless decls later. + CompleteTypeKind::AcceptSizeless, diag::err_typecheck_decl_incomplete_type)) { RealDecl->setInvalidDecl(); return; @@ -12254,8 +12257,10 @@ if (Ty->isDependentType()) return; // Require a complete type. - if (RequireCompleteType(VD->getLocation(), - Context.getBaseElementType(Ty), + if (RequireCompleteType(VD->getLocation(), Context.getBaseElementType(Ty), + // Sizeless variables can be initialized, + // so sizelessness itself isn't the problem. + CompleteTypeKind::AcceptSizeless, diag::err_typecheck_decl_incomplete_type)) { VD->setInvalidDecl(); return; @@ -12441,6 +12446,9 @@ if (!Var->hasAttr()) { if (RequireCompleteType(Var->getLocation(), Context.getBaseElementType(Type), + // Local variables can have sizeless type. + // We diagnose invalid sizeless decls later. + CompleteTypeKind::AcceptSizeless, diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); return; @@ -13822,6 +13830,8 @@ if (!ResultType->isDependentType() && !ResultType->isVoidType() && !FD->isInvalidDecl() && RequireCompleteType(FD->getLocation(), ResultType, + // Functions can return sizeless types by value. + CompleteTypeKind::AcceptSizeless, diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -250,6 +250,8 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { if (RequireCompleteType(Param->getLocation(), Param->getType(), + // Parameters can have sizeless type. + CompleteTypeKind::AcceptSizeless, diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); return true; @@ -15561,7 +15563,9 @@ DK = diag::err_catch_incomplete_ref; } if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) && - !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) + !BaseType->isDependentType() && + // See below for the handling of sizeless types. + RequireCompleteType(Loc, BaseType, CompleteTypeKind::AcceptSizeless, DK)) Invalid = true; if (!Invalid && Mode != 1 && BaseType->isSizelessType()) { diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -164,7 +164,10 @@ } if (!(PointeeT->isRecordType() && PointeeT->castAs()->isBeingDefined()) && - RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) + RequireCompleteType(Range.getBegin(), PointeeT, + // See below for the handling of sizeless types. + CompleteTypeKind::AcceptSizeless, DiagID, Kind, + Range)) return ReturnValueOnError; // The MSVC compatibility mode doesn't extend to sizeless types, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -973,6 +973,8 @@ if (!getLangOpts().CPlusPlus && RequireCompleteType(E->getExprLoc(), E->getType(), + // Function arguments can have sizeless type. + CompleteTypeKind::AcceptSizeless, diag::err_call_incomplete_argument)) return ExprError(); @@ -5281,6 +5283,8 @@ Arg = Args[ArgIx++]; if (RequireCompleteType(Arg->getBeginLoc(), ProtoArgType, + // Function arguments can have sizeless type. + CompleteTypeKind::AcceptSizeless, diag::err_call_incomplete_argument, Arg)) return true; @@ -6120,6 +6124,8 @@ } if (RequireCompleteType(Arg->getBeginLoc(), Arg->getType(), + // Function arguments can have sizeless type. + CompleteTypeKind::AcceptSizeless, diag::err_call_incomplete_argument, Arg)) return ExprError(); @@ -12234,6 +12240,9 @@ return QualType(); if (!RHS.get()->getType()->isVoidType()) S.RequireCompleteType(Loc, RHS.get()->getType(), + // Expressions of sizeless type are allowed + // on either side of ",". + Sema::CompleteTypeKind::AcceptSizeless, diag::err_incomplete_type); } @@ -14664,6 +14673,10 @@ if (!TInfo->getType()->isDependentType()) { if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(), + // Function arguments can have sizeless type and + // sizelessness doesn't prevent them from being + // passed through "...". + CompleteTypeKind::AcceptSizeless, diag::err_second_parameter_to_va_arg_incomplete, TInfo->getTypeLoc())) return ExprError(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -950,7 +950,8 @@ isPointer = true; } if (!isPointer || !Ty->isVoidType()) { - if (RequireCompleteType(ThrowLoc, Ty, + // See below for the handling of sizeless types. + if (RequireCompleteType(ThrowLoc, Ty, CompleteTypeKind::AcceptSizeless, isPointer ? diag::err_throw_incomplete_ptr : diag::err_throw_incomplete, E->getSourceRange())) @@ -1480,6 +1481,9 @@ // prvalue of the specified type that performs no initialization. if (!Ty->isVoidType() && RequireCompleteType(TyBeginLoc, ElemTy, + // Local sizeless objects can be initialized in the + // normal way. + CompleteTypeKind::AcceptSizeless, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); @@ -4635,7 +4639,8 @@ return true; return !S.RequireCompleteType( - Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); + Loc, ArgTy, Sema::CompleteTypeKind::AcceptSizeless, + diag::err_incomplete_type_used_in_type_trait_expr); } } @@ -5116,8 +5121,9 @@ if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; - if (S.RequireCompleteType(KWLoc, ArgTy, - diag::err_incomplete_type_used_in_type_trait_expr)) + if (S.RequireCompleteType( + KWLoc, ArgTy, Sema::CompleteTypeKind::AcceptSizeless, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; } @@ -5340,7 +5346,9 @@ return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. - if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) + if (!Self.isCompleteType(KeyLoc, RhsT, + Sema::CompleteTypeKind::AcceptSizeless) || + Self.isAbstractType(KeyLoc, RhsT)) return false; // Compute the result of add_rvalue_reference. @@ -5384,12 +5392,14 @@ // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, LhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + Self.RequireCompleteType( + KeyLoc, LhsT, Sema::CompleteTypeKind::AcceptSizeless, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + Self.RequireCompleteType( + KeyLoc, RhsT, Sema::CompleteTypeKind::AcceptSizeless, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; // cv void is never assignable. @@ -7793,6 +7803,8 @@ if (!E->getType()->isVoidType()) RequireCompleteType(E->getExprLoc(), E->getType(), + // Ignored results can have sizeless type. + CompleteTypeKind::AcceptSizeless, diag::err_incomplete_type); return E; } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1079,7 +1079,11 @@ else { if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled. !EncodedType->isVoidType()) // void is handled too. + // Leave later messages to complain about sizeless types that + // can't be @encoded. Sizelessness itself doesn't really prevent + // the use of @encode. if (RequireCompleteType(AtLoc, EncodedType, + CompleteTypeKind::AcceptSizeless, diag::err_incomplete_type_objc_at_encode, EncodedTypeInfo->getTypeLoc())) return ExprError(); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6194,6 +6194,8 @@ for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) { ParmVarDecl *Parm = Constructor->getParamDecl(I); if (S.RequireCompleteType(Loc, Parm->getType(), + // Function arguments can have sizeless type. + Sema::CompleteTypeKind::AcceptSizeless, diag::err_call_incomplete_argument)) break; @@ -8834,10 +8836,13 @@ case OR_No_Viable_Function: { auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args); - if (!S.RequireCompleteType(Kind.getLocation(), - DestType.getNonReferenceType(), - diag::err_typecheck_nonviable_condition_incomplete, - OnlyArg->getType(), Args[0]->getSourceRange())) + // Sizeless objects can be initialized, so sizelessness itself + // isn't the problem. Prefer the more detailed diagnostic below. + if (!S.RequireCompleteType( + Kind.getLocation(), DestType.getNonReferenceType(), + Sema::CompleteTypeKind::AcceptSizeless, + diag::err_typecheck_nonviable_condition_incomplete, + OnlyArg->getType(), Args[0]->getSourceRange())) S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << (Entity.getKind() == InitializedEntity::EK_Result) << OnlyArg->getType() << Args[0]->getSourceRange() diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -505,6 +505,8 @@ if (!LSI->ReturnType->isDependentType() && !LSI->ReturnType->isVoidType()) { if (RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType, + // Lambdas can return sizeless types. + CompleteTypeKind::AcceptSizeless, diag::err_lambda_incomplete_result)) { // Do nothing. } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4935,9 +4935,11 @@ ImplicitConversionSequence Result; Result.setBad(BadConversionSequence::no_conversion, From, ToType); - // We need a complete type for what follows. Incomplete types can never be - // initialized from init lists. - if (!S.isCompleteType(From->getBeginLoc(), ToType)) + // We need a completely-defined (but possibly sizeless) type for what + // follows. Incompletely-defined types can never be initialized from + // init lists. + if (!S.isCompleteType(From->getBeginLoc(), ToType, + Sema::CompleteTypeKind::AcceptSizeless)) return Result; // Per DR1467: @@ -7266,7 +7268,8 @@ &ConversionRef, VK_RValue); QualType ConversionType = Conversion->getConversionType(); - if (!isCompleteType(From->getBeginLoc(), ConversionType)) { + if (!isCompleteType(From->getBeginLoc(), ConversionType, + CompleteTypeKind::AcceptSizeless)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_final_conversion; return; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2420,7 +2420,10 @@ return StmtError(); QualType RangeType = Range->getType(); + // For sizeless types it's better to report the same "no viable + // 'begin' function" diagnostic as we would for scalars. if (RequireCompleteType(RangeLoc, RangeType, + CompleteTypeKind::AcceptSizeless, diag::err_for_range_incomplete_type)) return StmtError(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -7924,7 +7924,7 @@ bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) { BoundTypeDiagnoser<> Diagnoser(DiagID); - return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser); + return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser); } /// Ensure that the type T is a complete type. @@ -8555,7 +8555,10 @@ if (!T->isDependentType()) { // FIXME: It isn't entirely clear whether incomplete atomic types // are allowed or not; for simplicity, ban them for the moment. - if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0)) + // + // Fall through to the code below for sizeless types. + if (RequireCompleteType(Loc, T, CompleteTypeKind::AcceptSizeless, + diag::err_atomic_specifier_bad_type, 0)) return QualType(); int DisallowedKind = -1;