diff options
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 173 |
1 files changed, 110 insertions, 63 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a73093545aa7..aba00dc8ff9b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attrs.inc" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -1528,8 +1529,12 @@ void Sema::checkEnumArithmeticConversions(Expr *LHS, Expr *RHS, // are ill-formed. if (getLangOpts().CPlusPlus26) DiagID = diag::warn_conv_mixed_enum_types_cxx26; - else if (!L->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage() || - !R->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage()) { + else if (!L->castAsCanonical<EnumType>() + ->getOriginalDecl() + ->hasNameForLinkage() || + !R->castAsCanonical<EnumType>() + ->getOriginalDecl() + ->hasNameForLinkage()) { // If either enumeration type is unnamed, it's less likely that the // user cares about this, but this situation is still deprecated in // C++2a. Use a different warning group. @@ -6308,30 +6313,38 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, unsigned i = 0; SmallVector<QualType, 8> OverloadParams; - for (QualType ParamType : FT->param_types()) { + { + // The lvalue conversions in this loop are only for type resolution and + // don't actually occur. + EnterExpressionEvaluationContext Unevaluated( + *Sema, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(*Sema, /*ForValidityCheck=*/true); - // Convert array arguments to pointer to simplify type lookup. - ExprResult ArgRes = - Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]); - if (ArgRes.isInvalid()) - return nullptr; - Expr *Arg = ArgRes.get(); - QualType ArgType = Arg->getType(); - if (!ParamType->isPointerType() || - ParamType->getPointeeType().hasAddressSpace() || - !ArgType->isPointerType() || - !ArgType->getPointeeType().hasAddressSpace() || - isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) { - OverloadParams.push_back(ParamType); - continue; - } + for (QualType ParamType : FT->param_types()) { - QualType PointeeType = ParamType->getPointeeType(); - NeedsNewDecl = true; - LangAS AS = ArgType->getPointeeType().getAddressSpace(); + // Convert array arguments to pointer to simplify type lookup. + ExprResult ArgRes = + Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]); + if (ArgRes.isInvalid()) + return nullptr; + Expr *Arg = ArgRes.get(); + QualType ArgType = Arg->getType(); + if (!ParamType->isPointerType() || + ParamType->getPointeeType().hasAddressSpace() || + !ArgType->isPointerType() || + !ArgType->getPointeeType().hasAddressSpace() || + isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) { + OverloadParams.push_back(ParamType); + continue; + } - PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); - OverloadParams.push_back(Context.getPointerType(PointeeType)); + QualType PointeeType = ParamType->getPointeeType(); + NeedsNewDecl = true; + LangAS AS = ArgType->getPointeeType().getAddressSpace(); + + PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); + OverloadParams.push_back(Context.getPointerType(PointeeType)); + } } if (!NeedsNewDecl) @@ -7818,6 +7831,41 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, return prepareVectorSplat(DestTy, CastExpr); } +/// Check that a call to alloc_size function specifies sufficient space for the +/// destination type. +static void CheckSufficientAllocSize(Sema &S, QualType DestType, + const Expr *E) { + QualType SourceType = E->getType(); + if (!DestType->isPointerType() || !SourceType->isPointerType() || + DestType == SourceType) + return; + + const auto *CE = dyn_cast<CallExpr>(E->IgnoreParenCasts()); + if (!CE) + return; + + // Find the total size allocated by the function call. + if (!CE->getCalleeAllocSizeAttr()) + return; + std::optional<llvm::APInt> AllocSize = + CE->evaluateBytesReturnedByAllocSizeCall(S.Context); + // Allocations of size zero are permitted as a special case. They are usually + // done intentionally. + if (!AllocSize || AllocSize->isZero()) + return; + auto Size = CharUnits::fromQuantity(AllocSize->getZExtValue()); + + QualType TargetType = DestType->getPointeeType(); + // Find the destination size. As a special case function types have size of + // one byte to match the sizeof operator behavior. + auto LhsSize = TargetType->isFunctionType() + ? CharUnits::One() + : S.Context.getTypeSizeInCharsIfKnown(TargetType); + if (LhsSize && Size < LhsSize) + S.Diag(E->getExprLoc(), diag::warn_alloc_size) + << Size.getQuantity() << TargetType << LhsSize->getQuantity(); +} + ExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, @@ -7883,6 +7931,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); + CheckSufficientAllocSize(*this, castType, CastExpr); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } @@ -8605,16 +8655,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // If both operands are the same structure or union type, the result is that // type. - if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3 - if (const RecordType *RHSRT = RHSTy->getAs<RecordType>()) - if (declaresSameEntity(LHSRT->getOriginalDecl(), - RHSRT->getOriginalDecl())) - // "If both the operands have structure or union type, the result has - // that type." This implies that CV qualifiers are dropped. - return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), - RHSTy.getUnqualifiedType()); - // FIXME: Type of conditional expression must be complete in C mode. - } + // FIXME: Type of conditional expression must be complete in C mode. + if (LHSTy->isRecordType() && + Context.hasSameUnqualifiedType(LHSTy, RHSTy)) // C99 6.5.15p3 + return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), + RHSTy.getUnqualifiedType()); // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). @@ -9893,6 +9938,12 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); + // If assigning a void * created by an allocation function call to some other + // type, check that the allocated size is sufficient for that type. + if (result != AssignConvertType::Incompatible && + RHS.get()->getType()->isVoidPointerType()) + CheckSufficientAllocSize(*this, LHSType, RHS.get()); + // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. // CheckAssignmentConstraints allows the left-hand side to be a reference, @@ -11458,7 +11509,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, } static bool isScopedEnumerationType(QualType T) { - if (const EnumType *ET = T->getAs<EnumType>()) + if (const EnumType *ET = T->getAsCanonical<EnumType>()) return ET->getOriginalDecl()->isScoped(); return false; } @@ -12345,10 +12396,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, S.InvalidOperands(Loc, LHS, RHS); return QualType(); } - QualType IntType = LHSStrippedType->castAs<EnumType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType(); + QualType IntType = LHSStrippedType->castAsEnumDecl()->getIntegerType(); assert(IntType->isArithmeticType()); // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we @@ -13582,6 +13630,8 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { VarDecl *Var = dyn_cast<VarDecl>(Value); if (!Var) return NCCK_None; + if (Var->getType()->isReferenceType()) + return NCCK_None; assert(Var->hasLocalStorage() && "capture added 'const' to non-local?"); @@ -13785,7 +13835,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, // Then we append it to the list to check next in order. FieldTy = FieldTy.getCanonicalType(); - if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) { + if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) { if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } @@ -13801,7 +13851,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E, QualType Ty = E->getType(); assert(Ty->isRecordType() && "lvalue was not record?"); SourceRange Range = E->getSourceRange(); - const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>(); + const auto *RTy = Ty->getAsCanonical<RecordType>(); bool DiagEmitted = false; if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) @@ -16217,11 +16267,10 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, return ExprError(); // Look for the designated field. - const RecordType *RC = CurrentType->getAs<RecordType>(); - if (!RC) + auto *RD = CurrentType->getAsRecordDecl(); + if (!RD) return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) << CurrentType); - RecordDecl *RD = RC->getOriginalDecl()->getDefinitionOrSelf(); // C++ [lib.support.types]p5: // The macro offsetof accepts a restricted set of type arguments in this @@ -16618,8 +16667,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, auto *Var = cast<VarDecl>(Cap.getVariable()); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { - if (const RecordType *Record = - Cap.getCaptureType()->getAs<RecordType>()) { + if (auto *Record = Cap.getCaptureType()->getAsCXXRecordDecl()) { // The capture logic needs the destructor, so make sure we mark it. // Usually this is unnecessary because most local variables have // their destructors marked at declaration time, but parameters are @@ -16847,9 +16895,8 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // va_arg. Instead, get the underlying type of the enumeration and pass // that. QualType UnderlyingType = TInfo->getType(); - if (const auto *ET = UnderlyingType->getAs<EnumType>()) - UnderlyingType = - ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = UnderlyingType->getAsEnumDecl()) + UnderlyingType = ED->getIntegerType(); if (Context.typesAreCompatible(PromoteType, UnderlyingType, /*CompareUnqualified*/ true)) PromoteType = QualType(); @@ -18846,19 +18893,16 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, } // Prohibit structs with flexible array members too. // We cannot capture what is in the tail end of the struct. - if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) { - if (VTTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { - if (Diagnose) { - if (IsBlock) - S.Diag(Loc, diag::err_ref_flexarray_type); - else - S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var; - S.Diag(Var->getLocation(), diag::note_previous_decl) << Var; - } - return false; + if (const auto *VTD = Var->getType()->getAsRecordDecl(); + VTD && VTD->hasFlexibleArrayMember()) { + if (Diagnose) { + if (IsBlock) + S.Diag(Loc, diag::err_ref_flexarray_type); + else + S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var; + S.Diag(Var->getLocation(), diag::note_previous_decl) << Var; } + return false; } const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); // Lambdas and captured statements are not allowed to capture __block @@ -19938,7 +19982,7 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { // C++2a [basic.def.odr]p4: // [...] an expression of non-volatile-qualified non-class type to which // the lvalue-to-rvalue conversion is applied [...] - if (E->getType().isVolatileQualified() || E->getType()->getAs<RecordType>()) + if (E->getType().isVolatileQualified() || E->getType()->isRecordType()) return E; ExprResult Result = @@ -21440,8 +21484,11 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { // Expressions of unknown type. case BuiltinType::ArraySection: - Diag(E->getBeginLoc(), diag::err_array_section_use) - << cast<ArraySectionExpr>(E)->isOMPArraySection(); + // If we've already diagnosed something on the array section type, we + // shouldn't need to do any further diagnostic here. + if (!E->containsErrors()) + Diag(E->getBeginLoc(), diag::err_array_section_use) + << cast<ArraySectionExpr>(E)->isOMPArraySection(); return ExprError(); // Expressions of unknown type. |
