summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r--clang/lib/Sema/SemaExpr.cpp173
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.