diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 200 |
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; |
