diff options
author | John McCall <rjmccall@apple.com> | 2011-02-01 00:10:29 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-02-01 00:10:29 +0000 |
commit | 86c05f3f28bcf07c97dfb1881686fc43be2f47c2 (patch) | |
tree | 342fce9d2afec3117e45d47ba3f52ec76f534b28 | |
parent | 293a45e724a15fb58b8805a5791f9f3aee769cf6 (diff) |
Perform the bad-address-space conversions check as part of
CheckPointerTypesForAssignment.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124632 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 13 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 56 | ||||
-rw-r--r-- | test/PCH/types.c | 3 | ||||
-rw-r--r-- | test/Sema/address_spaces.c | 3 |
6 files changed, 54 insertions, 35 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 76045af1a8..3e7f48cf81 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1007,9 +1007,6 @@ def err_attribute_address_space_too_high : Error< "address space is larger than the maximum supported (%0)">; def err_attribute_address_multiple_qualifiers : Error< "multiple address spaces specified for type">; -def err_implicit_pointer_address_space_cast : Error< - "illegal implicit conversion between two pointers with different address " - "spaces">; def err_as_qualified_auto_decl : Error< "automatic variable qualified with an address space">; def err_arg_with_address_space : Error< @@ -2941,7 +2938,15 @@ def err_typecheck_convert_incompatible_block_pointer : Error< " %0 " "%select{from|to parameter of type|from a function with result type|to type|" "with an expression of type|to parameter of type|to type}2 %1">; - +def err_typecheck_incompatible_address_space : Error< + "%select{assigning %1 to %0" + "|passing %0 to parameter of type %1" + "|returning %0 from a function with result type %1" + "|converting %0 to type %1" + "|initializing %0 with an expression of type %1" + "|sending %0 to parameter of type %1" + "|casting %0 to type %1}2" + " changes address space of pointer">; def err_typecheck_convert_ambiguous : Error< "ambiguity in initializing value of type %0 with initializer of type %1">; def err_cannot_initialize_decl_noname : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b9b4342efb..f8cabf9c5f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4512,6 +4512,11 @@ public: /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, + /// IncompatiblePointerDiscardsQualifiers - The assignment + /// discards qualifiers that we don't permit to be discarded, + /// like address spaces. + IncompatiblePointerDiscardsQualifiers, + /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two /// levels differ e.g. char ** -> const char **, but we accept them as an diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 1fd12d3b7a..eda88881a4 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -206,15 +206,6 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, if (ExprTy == TypeTy) return; - if (Expr->getType()->isPointerType() && Ty->isPointerType()) { - QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); - QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); - if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { - Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) - << Expr->getSourceRange(); - } - } - // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. if (Kind == CK_DerivedToBase && diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0cad12c082..21bf4203e3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5356,20 +5356,28 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { assert(lhsType.isCanonical() && "LHS not canonicalized!"); assert(rhsType.isCanonical() && "RHS not canonicalized!"); - QualType lhptee, rhptee; - // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = lhsType->getAs<PointerType>()->getPointeeType(); - rhptee = rhsType->getAs<PointerType>()->getPointeeType(); + const Type *lhptee, *rhptee; + Qualifiers lhq, rhq; + llvm::tie(lhptee, lhq) = cast<PointerType>(lhsType)->getPointeeType().split(); + llvm::tie(rhptee, rhq) = cast<PointerType>(rhsType)->getPointeeType().split(); Sema::AssignConvertType ConvTy = Sema::Compatible; // C99 6.5.16.1p1: This following citation is common to constraints // 3 & 4 (below). ...and the type *pointed to* by the left has all the // qualifiers of the type *pointed to* by the right; - // FIXME: Handle ExtQualType - if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) - ConvTy = Sema::CompatiblePointerDiscardsQualifiers; + Qualifiers lq; + + if (!lhq.compatiblyIncludes(rhq)) { + // Treat address-space mismatches as fatal. TODO: address subspaces + if (lhq.getAddressSpace() != rhq.getAddressSpace()) + ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + + // For GCC compatibility, other qualifier mismatches are treated + // as still compatible in C. + else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; + } // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or // incomplete type and the other is a pointer to a qualified or unqualified @@ -5391,30 +5399,31 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { assert(lhptee->isFunctionType()); return Sema::FunctionVoidPointer; } + // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or // unqualified versions of compatible types, ... - lhptee = lhptee.getUnqualifiedType(); - rhptee = rhptee.getUnqualifiedType(); - if (!S.Context.typesAreCompatible(lhptee, rhptee)) { + QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0); + if (!S.Context.typesAreCompatible(ltrans, rtrans)) { // Check if the pointee types are compatible ignoring the sign. // We explicitly check for char so that we catch "char" vs // "unsigned char" on systems where "char" is unsigned. if (lhptee->isCharType()) - lhptee = S.Context.UnsignedCharTy; + ltrans = S.Context.UnsignedCharTy; else if (lhptee->hasSignedIntegerRepresentation()) - lhptee = S.Context.getCorrespondingUnsignedType(lhptee); + ltrans = S.Context.getCorrespondingUnsignedType(ltrans); if (rhptee->isCharType()) - rhptee = S.Context.UnsignedCharTy; + rtrans = S.Context.UnsignedCharTy; else if (rhptee->hasSignedIntegerRepresentation()) - rhptee = S.Context.getCorrespondingUnsignedType(rhptee); + rtrans = S.Context.getCorrespondingUnsignedType(rtrans); - if (lhptee == rhptee) { + if (ltrans == rtrans) { // Types are compatible ignoring the sign. Qualifier incompatibility // takes priority over sign incompatibility because the sign // warning can be disabled. if (ConvTy != Sema::Compatible) return ConvTy; + return Sema::IncompatiblePointerSign; } @@ -5424,11 +5433,11 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { // level of indirection, this must be the issue. if (isa<PointerType>(lhptee) && isa<PointerType>(rhptee)) { do { - lhptee = cast<PointerType>(lhptee)->getPointeeType(); - rhptee = cast<PointerType>(rhptee)->getPointeeType(); + lhptee = cast<PointerType>(lhptee)->getPointeeType().getTypePtr(); + rhptee = cast<PointerType>(rhptee)->getPointeeType().getTypePtr(); } while (isa<PointerType>(lhptee) && isa<PointerType>(rhptee)); - if (S.Context.hasSameUnqualifiedType(lhptee, rhptee)) + if (lhptee == rhptee) return Sema::IncompatibleNestedPointerQualifiers; } @@ -8680,6 +8689,17 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case FunctionVoidPointer: DiagKind = diag::ext_typecheck_convert_pointer_void_func; break; + case IncompatiblePointerDiscardsQualifiers: { + Qualifiers lhq = SrcType->getPointeeType().getQualifiers(); + Qualifiers rhq = DstType->getPointeeType().getQualifiers(); + if (lhq.getAddressSpace() != rhq.getAddressSpace()) { + DiagKind = diag::err_typecheck_incompatible_address_space; + break; + } + + llvm_unreachable("unknown error case for discarding qualifiers!"); + // fallthrough + } case CompatiblePointerDiscardsQualifiers: // If the qualifiers lost were because we were applying the // (deprecated) C++ conversion from a string literal to a char* diff --git a/test/PCH/types.c b/test/PCH/types.c index 73a2205b78..ba00dc6824 100644 --- a/test/PCH/types.c +++ b/test/PCH/types.c @@ -11,8 +11,7 @@ INT int_value; __attribute__((address_space(1))) int int_as_one; // TYPE_EXT_QUAL -ASInt *as_int_ptr1 = &int_value; // expected-error{{different address spaces}} \ - // FIXME: expected-warning{{discards qualifiers}} +ASInt *as_int_ptr1 = &int_value; // expected-error{{changes address space of pointer}} ASInt *as_int_ptr2 = &int_as_one; // FIXME: TYPE_FIXED_WIDTH_INT diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c index 538deda0c2..38b51b2912 100644 --- a/test/Sema/address_spaces.c +++ b/test/Sema/address_spaces.c @@ -36,7 +36,6 @@ struct _st { // rdar://6774906 __attribute__((address_space(256))) void * * const base = 0; void * get_0(void) { - return base[0]; // expected-error {{illegal implicit conversion between two pointers with different address spaces}} \ - expected-warning {{returning '__attribute__((address_space(256))) void *' from a function with result type 'void *' discards qualifiers}} + return base[0]; // expected-error {{returning '__attribute__((address_space(256))) void *' from a function with result type 'void *' changes address space of pointer}} } |