aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-02-01 00:10:29 +0000
committerJohn McCall <rjmccall@apple.com>2011-02-01 00:10:29 +0000
commit86c05f3f28bcf07c97dfb1881686fc43be2f47c2 (patch)
tree342fce9d2afec3117e45d47ba3f52ec76f534b28
parent293a45e724a15fb58b8805a5791f9f3aee769cf6 (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.td13
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--lib/Sema/Sema.cpp9
-rw-r--r--lib/Sema/SemaExpr.cpp56
-rw-r--r--test/PCH/types.c3
-rw-r--r--test/Sema/address_spaces.c3
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}}
}