summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp200
1 files changed, 107 insertions, 93 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6e777fb9aec8..077f4311ed72 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -286,6 +286,9 @@ static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) {
if (S.checkArgCount(TheCall, 1))
return true;
+ if (TheCall->getArg(0)->containsErrors())
+ return true;
+
ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
if (Arg.isInvalid())
return true;
@@ -2214,7 +2217,7 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
QualType ArgTy = Arg->getType();
- if (!ArgTy->isUnsignedIntegerType()) {
+ if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) {
S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
<< ArgTy;
@@ -2239,7 +2242,7 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) {
QualType Arg0Ty = Arg0->getType();
- if (!Arg0Ty->isUnsignedIntegerType()) {
+ if (!Arg0Ty->isUnsignedIntegerType() && !Arg0Ty->isExtVectorBoolType()) {
S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
<< Arg0Ty;
@@ -2282,7 +2285,7 @@ static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg,
}
static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) {
- if (S.checkArgCount(TheCall, 2))
+ if (S.checkArgCountRange(TheCall, 2, 3))
return ExprError();
Expr *MaskArg = TheCall->getArg(0);
@@ -2295,10 +2298,21 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) {
QualType PointeeTy = PtrTy->getPointeeType();
const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
const VectorType *DataVecTy = PointeeTy->getAs<VectorType>();
+
+ if (TheCall->getNumArgs() == 3) {
+ Expr *PassThruArg = TheCall->getArg(2);
+ QualType PassThruTy = PassThruArg->getType();
+ if (!S.Context.hasSameType(PassThruTy, PointeeTy))
+ return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
+ << /* third argument */ 3 << PointeeTy;
+ }
+
if (MaskVecTy->getNumElements() != DataVecTy->getNumElements())
return ExprError(
S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
- << "__builtin_masked_load" << MaskTy << PointeeTy);
+ << S.getASTContext().BuiltinInfo.getQuotedName(
+ TheCall->getBuiltinCallee())
+ << MaskTy << PointeeTy);
TheCall->setType(PointeeTy);
return TheCall;
@@ -2332,7 +2346,9 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) {
MaskVecTy->getNumElements() != PtrVecTy->getNumElements())
return ExprError(
S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
- << "__builtin_masked_store" << MaskTy << PointeeTy);
+ << S.getASTContext().BuiltinInfo.getQuotedName(
+ TheCall->getBuiltinCallee())
+ << MaskTy << PointeeTy);
if (!S.Context.hasSameType(ValTy, PointeeTy))
return ExprError(S.Diag(TheCall->getBeginLoc(),
@@ -2598,8 +2614,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
// TheCall will be freed by the smart pointer here, but that's fine, since
// BuiltinShuffleVector guts it, but then doesn't release it.
case Builtin::BI__builtin_masked_load:
+ case Builtin::BI__builtin_masked_expand_load:
return BuiltinMaskedLoad(*this, TheCall);
case Builtin::BI__builtin_masked_store:
+ case Builtin::BI__builtin_masked_compress_store:
return BuiltinMaskedStore(*this, TheCall);
case Builtin::BI__builtin_invoke:
return BuiltinInvoke(*this, TheCall);
@@ -5278,13 +5296,10 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
// extra checking to see what their promotable type actually is.
if (!Context.isPromotableIntegerType(Type))
return false;
- if (!Type->isEnumeralType())
+ const auto *ED = Type->getAsEnumDecl();
+ if (!ED)
return true;
- const EnumDecl *ED = Type->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
- return !(ED &&
- Context.typesAreCompatible(ED->getPromotionType(), Type));
+ return !Context.typesAreCompatible(ED->getPromotionType(), Type);
}()) {
unsigned Reason = 0;
if (Type->isReferenceType()) Reason = 1;
@@ -5536,16 +5551,6 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) {
<< Real->getSourceRange() << Imag->getSourceRange();
}
- // We don't allow _Complex _Float16 nor _Complex __fp16 as type specifiers;
- // don't allow this builtin to form those types either.
- // FIXME: Should we allow these types?
- if (Real->getType()->isFloat16Type())
- return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
- << "_Float16";
- if (Real->getType()->isHalfType())
- return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
- << "half";
-
TheCall->setType(Context.getComplexType(Real->getType()));
return false;
}
@@ -7891,16 +7896,10 @@ bool DecomposePrintfHandler::HandlePrintfSpecifier(
template<typename MemberKind>
static llvm::SmallPtrSet<MemberKind*, 1>
CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
- const RecordType *RT = Ty->getAs<RecordType>();
+ auto *RD = Ty->getAsCXXRecordDecl();
llvm::SmallPtrSet<MemberKind*, 1> Results;
- if (!RT)
- return Results;
- CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl());
- if (!RD)
- return Results;
- RD = RD->getDefinition();
- if (!RD)
+ if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition()))
return Results;
LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(),
@@ -8438,10 +8437,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
bool IsEnum = false;
bool IsScopedEnum = false;
QualType IntendedTy = ExprTy;
- if (auto EnumTy = ExprTy->getAs<EnumType>()) {
- IntendedTy =
- EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
- if (EnumTy->isUnscopedEnumerationType()) {
+ if (const auto *ED = ExprTy->getAsEnumDecl()) {
+ IntendedTy = ED->getIntegerType();
+ if (!ED->isScoped()) {
ExprTy = IntendedTy;
// This controls whether we're talking about the underlying type or not,
// which we only want to do when it's an unscoped enum.
@@ -9741,10 +9739,7 @@ struct SearchNonTrivialToInitializeField
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
}
void visitStruct(QualType FT, SourceLocation SL) {
- for (const FieldDecl *FD : FT->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->fields())
+ for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
visit(FD->getType(), FD->getLocation());
}
void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK,
@@ -9789,10 +9784,7 @@ struct SearchNonTrivialToCopyField
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
}
void visitStruct(QualType FT, SourceLocation SL) {
- for (const FieldDecl *FD : FT->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->fields())
+ for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
visit(FD->getType(), FD->getLocation());
}
void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT,
@@ -10063,17 +10055,16 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
PDiag(diag::warn_arc_object_memaccess)
<< ArgIdx << FnName << PointeeTy
<< Call->getCallee()->getSourceRange());
- else if (const auto *RT = PointeeTy->getAs<RecordType>()) {
+ else if (const auto *RD = PointeeTy->getAsRecordDecl()) {
// FIXME: Do not consider incomplete types even though they may be
// completed later. GCC does not diagnose such code, but we may want to
// consider diagnosing it in the future, perhaps under a different, but
// related, diagnostic group.
bool NonTriviallyCopyableCXXRecord =
- getLangOpts().CPlusPlus && !RT->isIncompleteType() &&
- !RT->desugar().isTriviallyCopyableType(Context);
+ getLangOpts().CPlusPlus && RD->isCompleteDefinition() &&
+ !PointeeTy.isTriviallyCopyableType(Context);
- const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
RD->isNonTrivialToPrimitiveDefaultInitialize()) {
DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
@@ -10593,20 +10584,15 @@ struct IntRange {
if (!C.getLangOpts().CPlusPlus) {
// For enum types in C code, use the underlying datatype.
- if (const auto *ET = dyn_cast<EnumType>(T))
- T = ET->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->getIntegerType()
- .getDesugaredType(C)
- .getTypePtr();
- } else if (const auto *ET = dyn_cast<EnumType>(T)) {
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType().getDesugaredType(C).getTypePtr();
+ } else if (auto *Enum = T->getAsEnumDecl()) {
// For enum types in C++, use the known bit width of the enumerators.
- EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf();
// In C++11, enums can have a fixed underlying type. Use this type to
// compute the range.
if (Enum->isFixed()) {
return IntRange(C.getIntWidth(QualType(T, 0)),
- !ET->isSignedIntegerOrEnumerationType());
+ !Enum->getIntegerType()->isSignedIntegerType());
}
unsigned NumPositive = Enum->getNumPositiveBits();
@@ -10642,10 +10628,8 @@ struct IntRange {
T = CT->getElementType().getTypePtr();
if (const AtomicType *AT = dyn_cast<AtomicType>(T))
T = AT->getValueType().getTypePtr();
- if (const EnumType *ET = dyn_cast<EnumType>(T))
- T = C.getCanonicalType(
- ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType())
- .getTypePtr();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = C.getCanonicalType(ED->getIntegerType()).getTypePtr();
if (const auto *EIT = dyn_cast<BitIntType>(T))
return IntRange(EIT->getNumBits(), EIT->isUnsigned());
@@ -11616,10 +11600,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
if (BitfieldType->isBooleanType())
return false;
- if (BitfieldType->isEnumeralType()) {
- EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) {
// If the underlying enum type was not explicitly specified as an unsigned
// type and the enum contain only positive values, MSVC++ will cause an
// inconsistency by storing this as a signed type.
@@ -11648,15 +11629,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// The RHS is not constant. If the RHS has an enum type, make sure the
// bitfield is wide enough to hold all the values of the enum without
// truncation.
- const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>();
+ const auto *ED = OriginalInit->getType()->getAsEnumDecl();
const PreferredTypeAttr *PTAttr = nullptr;
- if (!EnumTy) {
+ if (!ED) {
PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
if (PTAttr)
- EnumTy = PTAttr->getType()->getAs<EnumType>();
+ ED = PTAttr->getType()->getAsEnumDecl();
}
- if (EnumTy) {
- EnumDecl *ED = EnumTy->getOriginalDecl()->getDefinitionOrSelf();
+ if (ED) {
bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType();
// Enum types are implicitly signed on Windows, so check if there are any
@@ -12720,8 +12700,8 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
// type, to give us better diagnostics.
Source = Context.getCanonicalType(SourceType).getTypePtr();
- if (const EnumType *SourceEnum = Source->getAs<EnumType>())
- if (const EnumType *TargetEnum = Target->getAs<EnumType>())
+ if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>())
+ if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>())
if (SourceEnum->getOriginalDecl()->hasNameForLinkage() &&
TargetEnum->getOriginalDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
@@ -15361,17 +15341,14 @@ static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) {
if (TC1 != TC2)
return false;
- if (TC1 == Type::Enum) {
- return isLayoutCompatible(
- C, cast<EnumType>(T1)->getOriginalDecl()->getDefinitionOrSelf(),
- cast<EnumType>(T2)->getOriginalDecl()->getDefinitionOrSelf());
- } else if (TC1 == Type::Record) {
+ if (TC1 == Type::Enum)
+ return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl());
+ if (TC1 == Type::Record) {
if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType())
return false;
- return isLayoutCompatible(
- C, cast<RecordType>(T1)->getOriginalDecl()->getDefinitionOrSelf(),
- cast<RecordType>(T2)->getOriginalDecl()->getDefinitionOrSelf());
+ return isLayoutCompatible(C, T1->castAsRecordDecl(),
+ T2->castAsRecordDecl());
}
return false;
@@ -15728,9 +15705,7 @@ void Sema::RefersToMemberWithReducedAlignment(
return;
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
- RecordDecl *RD = BaseType->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *RD = BaseType->castAsRecordDecl();
if (RD->isInvalidDecl())
return;
@@ -15891,6 +15866,54 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
return false;
}
+/// Check if all arguments have the same type. If the types don't match, emit an
+/// error message and return true. Otherwise return false.
+///
+/// For scalars we directly compare their unqualified types. But even if we
+/// compare unqualified vector types, a difference in qualifiers in the element
+/// types can make the vector types be considered not equal. For example,
+/// vector of 4 'const float' values vs vector of 4 'float' values.
+/// So we compare unqualified types of their elements and number of elements.
+static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef,
+ ArrayRef<Expr *> Args) {
+ assert(!Args.empty() && "Should have at least one argument.");
+
+ Expr *Arg0 = Args.front();
+ QualType Ty0 = Arg0->getType();
+
+ auto EmitError = [&](Expr *ArgI) {
+ SemaRef.Diag(Arg0->getBeginLoc(),
+ diag::err_typecheck_call_different_arg_types)
+ << Arg0->getType() << ArgI->getType();
+ };
+
+ // Compare scalar types.
+ if (!Ty0->isVectorType()) {
+ for (Expr *ArgI : Args.drop_front())
+ if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) {
+ EmitError(ArgI);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Compare vector types.
+ const auto *Vec0 = Ty0->castAs<VectorType>();
+ for (Expr *ArgI : Args.drop_front()) {
+ const auto *VecI = ArgI->getType()->getAs<VectorType>();
+ if (!VecI ||
+ !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(),
+ VecI->getElementType()) ||
+ Vec0->getNumElements() != VecI->getNumElements()) {
+ EmitError(ArgI);
+ return true;
+ }
+ }
+
+ return false;
+}
+
std::optional<QualType>
Sema::BuiltinVectorMath(CallExpr *TheCall,
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
@@ -15912,15 +15935,12 @@ Sema::BuiltinVectorMath(CallExpr *TheCall,
SourceLocation LocA = Args[0]->getBeginLoc();
QualType TyA = Args[0]->getType();
- QualType TyB = Args[1]->getType();
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
return std::nullopt;
- if (!Context.hasSameUnqualifiedType(TyA, TyB)) {
- Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
+ if (checkBuiltinVectorMathArgTypes(*this, Args))
return std::nullopt;
- }
TheCall->setArg(0, Args[0]);
TheCall->setArg(1, Args[1]);
@@ -15955,17 +15975,11 @@ bool Sema::BuiltinElementwiseTernaryMath(
return true;
}
- TheCall->setArg(0, Args[0]);
- for (int I = 1; I < 3; ++I) {
- if (Args[0]->getType().getCanonicalType() !=
- Args[I]->getType().getCanonicalType()) {
- return Diag(Args[0]->getBeginLoc(),
- diag::err_typecheck_call_different_arg_types)
- << Args[0]->getType() << Args[I]->getType();
- }
+ if (checkBuiltinVectorMathArgTypes(*this, Args))
+ return true;
+ for (int I = 0; I < 3; ++I)
TheCall->setArg(I, Args[I]);
- }
TheCall->setType(Args[0]->getType());
return false;