From: Douglas Gregor Date: Fri, 23 Jan 2009 00:36:41 +0000 (+0000) Subject: Support arithmetic on pointer-to-function types as a GNU X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c983b86514d14dd4b30147bf6791dde9487d2c3f;p=clang Support arithmetic on pointer-to-function types as a GNU extension. Addresses clang PR/3371. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62823 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 259265c2bf..1858f2583b 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -345,7 +345,9 @@ DIAG(ext_gnu_old_style_field_designator, EXTENSION, "use of GNU old-style field designator extension") DIAG(ext_gnu_case_range, EXTENSION, "use of GNU case range extension") - +DIAG(ext_gnu_ptr_func_arith, EXTENSION, + "arithmetic on pointer to function type %0 is a GNU extension") + // Generic errors. DIAG(err_parse_error, ERROR, "parse error") @@ -1262,6 +1264,8 @@ DIAG(err_typecheck_arithmetic_incomplete_type, ERROR, "arithmetic on pointer to incomplete type %0") DIAG(err_typecheck_pointer_arith_function_type, ERROR, "arithmetic on pointer to function type %0") +DIAG(err_typecheck_pointer_arith_void_type, ERROR, + "arithmetic on pointer to void type") DIAG(err_typecheck_decl_incomplete_type, ERROR, "variable has incomplete type %0") // FIXME: Use %select diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8cf153e673..ab5bd6bd11 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2656,12 +2656,25 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 // Check for arithmetic on pointers to incomplete types if (!PTy->getPointeeType()->isObjectType()) { if (PTy->getPointeeType()->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + // GNU extension: arithmetic on pointer to void Diag(Loc, diag::ext_gnu_void_ptr) << lex->getSourceRange() << rex->getSourceRange(); } else if (PTy->getPointeeType()->isFunctionType()) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) + << lex->getType() << lex->getSourceRange(); + return QualType(); + } + + // GNU extension: arithmetic on pointer to function + Diag(Loc, diag::ext_gnu_ptr_func_arith) << lex->getType() << lex->getSourceRange(); - return QualType(); } else { DiagnoseIncompleteType(Loc, PTy->getPointeeType(), diag::err_typecheck_arithmetic_incomplete_type, @@ -2701,6 +2714,16 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, if (lpointee->isVoidType()) { Diag(Loc, diag::ext_gnu_void_ptr) << lex->getSourceRange() << rex->getSourceRange(); + } else if (lpointee->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) + << lex->getType() << lex->getSourceRange(); + return QualType(); + } + + // GNU extension: arithmetic on pointer to function + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << lex->getType() << lex->getSourceRange(); } else { Diag(Loc, diag::err_typecheck_sub_ptr_object) << lex->getType() << lex->getSourceRange(); @@ -3174,10 +3197,22 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, if (PT->getPointeeType()->isObjectType()) { // Pointer to object is ok! } else if (PT->getPointeeType()->isVoidType()) { - // Pointer to void is extension. + if (getLangOptions().CPlusPlus) { + Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) + << Op->getSourceRange(); + return QualType(); + } + + // Pointer to void is a GNU extension in C. Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); } else if (PT->getPointeeType()->isFunctionType()) { - Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) + if (getLangOptions().CPlusPlus) { + Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) + << Op->getType() << Op->getSourceRange(); + return QualType(); + } + + Diag(OpLoc, diag::ext_gnu_ptr_func_arith) << ResType << Op->getSourceRange(); return QualType(); } else { diff --git a/test/Sema/pointer-addition.c b/test/Sema/pointer-addition.c index 95f364fc67..81a1dc06c1 100644 --- a/test/Sema/pointer-addition.c +++ b/test/Sema/pointer-addition.c @@ -2,13 +2,18 @@ typedef struct S S; // expected-note{{forward declaration of 'struct S'}} void a(S* b, void* c) { + void (*fp)(int) = 0; b++; // expected-error {{arithmetic on pointer to incomplete type}} b += 1; // expected-error {{arithmetic on pointer to incomplete type}} c++; // expected-warning {{use of GNU void* extension}} c += 1; // expected-warning {{use of GNU void* extension}} + c--; // expected-warning {{use of GNU void* extension}} + c -= 1; // expected-warning {{use of GNU void* extension}} b = 1+b; // expected-error {{arithmetic on pointer to incomplete type}} /* The next couple tests are only pedantic warnings in gcc */ void (*d)(S*,void*) = a; - d += 1; // expected-error {{arithmetic on pointer to function type}}} - d++; // expected-error {{arithmetic on pointer to function type}}} + d += 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} + d++; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}} + d--; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} + d -= 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} }