Change Sema::CheckAddressOfOperation() to respect C99-only addressof rules.
Remove diagnostics from Sema::CheckIndirectionOperand(). C89/C99 allow dereferencing an incomplete type. clang appears to be emulating some incorrect gcc behavior (see below).
void
foo (void)
{
struct b;
struct b* x = 0;
struct b* y = &*x; // gcc produces an error ("dereferencing pointer to incomplete type")
}
With this patch, the above is now allowed.
Bug/Patch by Eli Friedman!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45933 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp
index 73c1687..ced6953 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -1618,6 +1618,17 @@
/// Note: The usual conversions are *not* applied to the operand of the &
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
+ if (getLangOptions().C99) {
+ // Implement C99-only parts of addressof rules.
+ if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
+ if (uOp->getOpcode() == UnaryOperator::Deref)
+ // Per C99 6.5.3.2, the address of a deref always returns a valid result
+ // (assuming the deref expression is valid).
+ return uOp->getSubExpr()->getType();
+ }
+ // Technically, there should be a check for array subscript
+ // expressions here, but the result of one is always an lvalue anyway.
+ }
Decl *dcl = getPrimaryDeclaration(op);
Expr::isLvalueResult lval = op->isLvalue();
@@ -1651,19 +1662,12 @@
QualType qType = op->getType();
if (const PointerType *PT = qType->getAsPointerType()) {
- QualType ptype = PT->getPointeeType();
- // C99 6.5.3.2p4. "if it points to an object,...".
- if (ptype->isIncompleteType()) { // An incomplete type is not an object
- // GCC compat: special case 'void *' (treat as extension, not error).
- if (ptype->isVoidType()) {
- Diag(OpLoc, diag::ext_typecheck_deref_ptr_to_void,op->getSourceRange());
- } else {
- Diag(OpLoc, diag::err_typecheck_deref_incomplete_type,
- ptype.getAsString(), op->getSourceRange());
- return QualType();
- }
- }
- return ptype;
+ // Note that per both C89 and C99, this is always legal, even
+ // if ptype is an incomplete type or void.
+ // It would be possible to warn about dereferencing a
+ // void pointer, but it's completely well-defined,
+ // and such a warning is unlikely to catch any mistakes.
+ return PT->getPointeeType();
}
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer,
qType.getAsString(), op->getSourceRange());
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 90a900a..ea6da36 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -756,10 +756,6 @@
"invalid argument type to unary expression '%0'")
DIAG(err_typecheck_indirection_requires_pointer, ERROR,
"indirection requires pointer operand ('%0' invalid)")
-DIAG(err_typecheck_deref_incomplete_type, ERROR,
- "dereferencing pointer to incomplete type '%0'")
-DIAG(ext_typecheck_deref_ptr_to_void, WARNING,
- "dereferencing void pointer")
DIAG(err_typecheck_invalid_operands, ERROR,
"invalid operands to binary expression ('%0' and '%1')")
DIAG(err_typecheck_sub_ptr_object, ERROR,
diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c
index f6b9d1f..87fe2d2 100644
--- a/test/Sema/conditional-expr.c
+++ b/test/Sema/conditional-expr.c
@@ -1,7 +1,7 @@
// RUN: clang -fsyntax-only -verify -pedantic %s
void foo() {
*(0 ? (double *)0 : (void *)0) = 0;
- *((void *) 0) = 0; // -expected-warning {{dereferencing void pointer}} -expected-error {{incomplete type 'void' is not assignable}}
+ *((void *) 0) = 0; // -expected-error {{incomplete type 'void' is not assignable}}
double *dp;
int *ip;
void *vp;
diff --git a/test/Sema/deref.c b/test/Sema/deref.c
new file mode 100644
index 0000000..87f1b48
--- /dev/null
+++ b/test/Sema/deref.c
@@ -0,0 +1,22 @@
+// RUN: clang -fsyntax-only -verify -std=c90 %s
+void
+foo (void)
+{
+ struct b;
+ struct b* x = 0;
+ struct b* y = &*x;
+}
+
+void foo2 (void)
+{
+ typedef int (*arrayptr)[];
+ arrayptr x = 0;
+ arrayptr y = &*x;
+}
+
+void foo3 (void)
+{
+ void* x = 0;
+ void* y = &*x; // expected-error {{invalid lvalue in address expression}}
+}
+