From 5cc2c8b9c307edd156cc4622490a2f9447d90702 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 23 Jul 2010 15:58:24 +0000 Subject: [PATCH] Vectors are not integer types, so the type system should not classify them as such. Type::is(Signed|Unsigned|)IntegerType() now return false for vector types, and new functions has(Signed|Unsigned|)IntegerRepresentation() cover integer types and vector-of-integer types. This fixes a bunch of latent bugs. Patch from Anton Yartsev! llvm-svn: 109229 --- clang/include/clang/AST/CanonicalType.h | 3 +++ clang/include/clang/AST/Type.h | 14 ++++++++++++- clang/lib/AST/ASTContext.cpp | 6 +++--- clang/lib/AST/Type.cpp | 27 ++++++++++++++++++------- clang/lib/CodeGen/CGCall.cpp | 4 ++-- clang/lib/CodeGen/CGExprScalar.cpp | 12 +++++------ clang/lib/Sema/SemaChecking.cpp | 10 ++++----- clang/lib/Sema/SemaExpr.cpp | 26 +++++++++++++++--------- clang/lib/Sema/SemaExprObjC.cpp | 5 ++--- clang/lib/Sema/SemaType.cpp | 3 +-- clang/test/Sema/vector-ops.c | 25 +++++++++++++++++++++++ 11 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 clang/test/Sema/vector-ops.c diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 9f97fd8a7aee..a1023a2810da 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -273,6 +273,9 @@ public: LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasSignedIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasUnsignedIntegerRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasFloatingRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 4c148e8fa221..e8721058a7db 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -952,10 +952,22 @@ public: /// an objective pointer type for the purpose of GC'ability bool hasObjCPointerRepresentation() const; + /// \brief Determine whether this type has an integer representation + /// of some sort, e.g., it is an integer type or a vector. + bool hasIntegerRepresentation() const; + + /// \brief Determine whether this type has an signed integer representation + /// of some sort, e.g., it is an signed integer type or a vector. + bool hasSignedIntegerRepresentation() const; + + /// \brief Determine whether this type has an unsigned integer representation + /// of some sort, e.g., it is an unsigned integer type or a vector. + bool hasUnsignedIntegerRepresentation() const; + /// \brief Determine whether this type has a floating-point representation /// of some sort, e.g., it is a floating-point type or a vector thereof. bool hasFloatingRepresentation() const; - + // Type Checking Functions: Check to see if this type is structurally the // specified type, ignoring typedefs and qualifiers, and return a pointer to // the best type we can. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 03e91f101ed7..330f42e83535 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5031,7 +5031,7 @@ unsigned ASTContext::getIntWidth(QualType T) { } QualType ASTContext::getCorrespondingUnsignedType(QualType T) { - assert(T->isSignedIntegerType() && "Unexpected type"); + assert(T->hasSignedIntegerRepresentation() && "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> if (const VectorType *VTy = T->getAs()) @@ -5411,8 +5411,8 @@ ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { // Finally, we have two differing integer types. // The rules for this case are in C99 6.3.1.8 int compare = getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->isSignedIntegerType(), - rhsSigned = rhs->isSignedIntegerType(); + bool lhsSigned = lhs->hasSignedIntegerRepresentation(), + rhsSigned = rhs->hasSignedIntegerRepresentation(); QualType destType; if (lhsSigned == rhsSigned) { // Same signedness; use the higher-ranked type diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index d7929304233f..99db0b24238b 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -434,9 +434,14 @@ bool Type::isIntegerType() const { // FIXME: In C++, enum types are never integer types. if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) return true; + return false; +} + +bool Type::hasIntegerRepresentation() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); - return false; + else + return isIntegerType(); } /// \brief Determine whether this type is an integral type. @@ -523,8 +528,7 @@ bool Type::isAnyCharacterType() const { /// isSignedIntegerType - Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], -/// an enum decl which has a signed representation, or a vector of signed -/// integer element type. +/// an enum decl which has a signed representation bool Type::isSignedIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && @@ -534,15 +538,19 @@ bool Type::isSignedIntegerType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + return false; +} + +bool Type::hasSignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); - return false; + else + return isSignedIntegerType(); } /// isUnsignedIntegerType - Return true if this is an integer type that is /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum -/// decl which has an unsigned representation, or a vector of unsigned integer -/// element type. +/// decl which has an unsigned representation bool Type::isUnsignedIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && @@ -552,9 +560,14 @@ bool Type::isUnsignedIntegerType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + return false; +} + +bool Type::hasUnsignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); - return false; + else + return isUnsignedIntegerType(); } bool Type::isFloatingType() const { diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index b22e349d9520..30b2b6e1201a 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -730,9 +730,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Extend: - if (RetTy->isSignedIntegerType()) { + if (RetTy->hasSignedIntegerRepresentation()) { RetAttrs |= llvm::Attribute::SExt; - } else if (RetTy->isUnsignedIntegerType()) { + } else if (RetTy->hasUnsignedIntegerRepresentation()) { RetAttrs |= llvm::Attribute::ZExt; } // FALLTHROUGH diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index d25f6e9acf60..84e3b966c78d 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -297,7 +297,7 @@ public: // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { - if (Ops.Ty->isSignedIntegerType()) { + if (Ops.Ty->hasSignedIntegerRepresentation()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -1422,7 +1422,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); - else if (Ops.Ty->isUnsignedIntegerType()) + else if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div"); else return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div"); @@ -1523,7 +1523,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { if (!Ops.Ty->isAnyPointerType()) { - if (Ops.Ty->isSignedIntegerType()) { + if (Ops.Ty->hasSignedIntegerRepresentation()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add"); @@ -1606,7 +1606,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { if (!isa(Ops.LHS->getType())) { - if (Ops.Ty->isSignedIntegerType()) { + if (Ops.Ty->hasSignedIntegerRepresentation()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub"); @@ -1747,7 +1747,7 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { CGF.EmitBlock(Cont); } - if (Ops.Ty->isUnsignedIntegerType()) + if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); } @@ -1791,7 +1791,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, if (LHS->getType()->isFPOrFPVectorTy()) { Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc, LHS, RHS, "cmp"); - } else if (LHSTy->isSignedIntegerType()) { + } else if (LHSTy->hasSignedIntegerRepresentation()) { Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc, LHS, RHS, "cmp"); } else { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2887a50d527e..e376dfab57c8 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -780,7 +780,7 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { // with mask. If so, verify that RHS is an integer vector type with the // same number of elts as lhs. if (TheCall->getNumArgs() == 2) { - if (!RHSType->isIntegerType() || + if (!RHSType->hasIntegerRepresentation() || RHSType->getAs()->getNumElements() != numElements) Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) << SourceRange(TheCall->getArg(1)->getLocStart(), @@ -2453,7 +2453,7 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // We don't do anything special if this isn't an unsigned integral // comparison: we're only interested in integral comparisons, and // signed comparisons only happen in cases we don't care to warn about. - if (!T->isUnsignedIntegerType()) + if (!T->hasUnsignedIntegerRepresentation()) return AnalyzeImpConvsInComparison(S, E); Expr *lex = E->getLHS()->IgnoreParenImpCasts(); @@ -2462,12 +2462,12 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; - if (lex->getType()->isSignedIntegerType()) { - assert(!rex->getType()->isSignedIntegerType() && + if (lex->getType()->hasSignedIntegerRepresentation()) { + assert(!rex->getType()->hasSignedIntegerRepresentation() && "unsigned comparison between two signed integer expressions?"); signedOperand = lex; unsignedOperand = rex; - } else if (rex->getType()->isSignedIntegerType()) { + } else if (rex->getType()->hasSignedIntegerRepresentation()) { signedOperand = rex; unsignedOperand = lex; } else { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d2f68e03311d..0d53e2f8beaa 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2362,8 +2362,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, << LHSExp->getSourceRange() << RHSExp->getSourceRange()); } // C99 6.5.2.1p1 - if (!(IndexExpr->getType()->isIntegerType() && - IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent()) + if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent()) return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer) << IndexExpr->getSourceRange()); @@ -4576,12 +4575,12 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { // "unsigned char" on systems where "char" is unsigned. if (lhptee->isCharType()) lhptee = Context.UnsignedCharTy; - else if (lhptee->isSignedIntegerType()) + else if (lhptee->hasSignedIntegerRepresentation()) lhptee = Context.getCorrespondingUnsignedType(lhptee); if (rhptee->isCharType()) rhptee = Context.UnsignedCharTy; - else if (rhptee->isSignedIntegerType()) + else if (rhptee->hasSignedIntegerRepresentation()) rhptee = Context.getCorrespondingUnsignedType(rhptee); if (lhptee == rhptee) { @@ -5078,7 +5077,8 @@ QualType Sema::CheckMultiplyDivideOperands( QualType Sema::CheckRemainderOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + if (lex->getType()->hasIntegerRepresentation() && + rex->getType()->hasIntegerRepresentation()) return CheckVectorOperands(Loc, lex, rex); return InvalidOperands(Loc, lex, rex); } @@ -5323,7 +5323,8 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { // C99 6.5.7p2: Each of the operands shall have integer type. - if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + if (!lex->getType()->hasIntegerRepresentation() || + !rex->getType()->hasIntegerRepresentation()) return InvalidOperands(Loc, lex, rex); // Vector shifts promote their scalar inputs to vector type. @@ -5777,7 +5778,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, // Return the type for the comparison, which is the same as vector type for // integer vectors, or an integer type of identical size and number of // elements for floating point vectors. - if (lType->isIntegerType()) + if (lType->hasIntegerRepresentation()) return lType; const VectorType *VTy = lType->getAs(); @@ -5794,8 +5795,13 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, inline QualType Sema::CheckBitwiseOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) - return CheckVectorOperands(Loc, lex, rex); + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + if (lex->getType()->hasIntegerRepresentation() && + rex->getType()->hasIntegerRepresentation()) + return CheckVectorOperands(Loc, lex, rex); + + return InvalidOperands(Loc, lex, rex); + } QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); @@ -6702,7 +6708,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) << resultType << Input->getSourceRange(); - else if (!resultType->isIntegerType()) + else if (!resultType->hasIntegerRepresentation()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input->getSourceRange()); break; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 5132464d244f..b0f9b2cd246a 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -967,9 +967,8 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && - (ReceiverType->isPointerType() || - (ReceiverType->isIntegerType() && - ReceiverType->isScalarType()))) { + (ReceiverType->isPointerType() || + ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index cff2f5776f9d..0734e74b17f4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1944,8 +1944,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, return; } // the base type must be integer or float, and can't already be a vector. - if (CurType->isVectorType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { + if (!CurType->isIntegerType() && !CurType->isRealFloatingType()) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; Attr.setInvalid(); return; diff --git a/clang/test/Sema/vector-ops.c b/clang/test/Sema/vector-ops.c new file mode 100644 index 000000000000..20575ec510c3 --- /dev/null +++ b/clang/test/Sema/vector-ops.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversions +typedef unsigned int v2u __attribute__ ((vector_size (8))); +typedef int v2s __attribute__ ((vector_size (8))); +typedef float v2f __attribute__ ((vector_size(8))); + +void test1(v2u v2ua, v2s v2sa, v2f v2fa) { + // Bitwise binary operators + (void)(v2ua & v2ua); + (void)(v2fa & v2fa); // expected-error{{invalid operands to binary expression}} + + // Unary operators + (void)(~v2ua); + (void)(~v2fa); // expected-error{{invalid argument type 'v2f' to unary}} + + // Arrays + int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u'}} + int array2[17]; + // FIXME: error message below needs type! + (void)(array2[v2ua]); // expected-error{{array subscript is not an integer}} + + v2u *v2u_ptr = 0; + v2s *v2s_ptr; + v2s_ptr = v2u_ptr; // expected-warning{{converts between pointers to integer types with different sign}} +} +