diff --git a/src/pike_compiler.h b/src/pike_compiler.h
index b661db1d8931abc5b02040718d687d2cce59882a..001c8571dc064573ccec4c547cc35919024aea37 100644
--- a/src/pike_compiler.h
+++ b/src/pike_compiler.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: pike_compiler.h,v 1.10 2008/05/02 10:56:06 grubba Exp $
+|| $Id: pike_compiler.h,v 1.11 2008/05/03 20:06:06 grubba Exp $
 */
 
 #ifndef PIKE_COMPILER_H
@@ -80,5 +80,7 @@ struct compilation
 #define PC_GET_DEFAULT_MODULE_FUN_NUM			5
 #define PC_CHANGE_COMPILER_COMPATIBILITY_FUN_NUM	6
 #define PC_HANDLE_INHERIT_FUN_NUM			7
+#define PC_POP_TYPE_ATTRIBUTE_FUN_NUM			8
+#define PC_PUSH_TYPE_ATTRIBUTE_FUN_NUM			9
 
 #endif	/* !PIKE_COMPILER_H */
diff --git a/src/pike_types.c b/src/pike_types.c
index 9f873066fba5c2125fc0b9873057923d3d152a44..1059b8ebb2f98fdd8a44fc0f7961cc79ee25c9cc 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: pike_types.c,v 1.323 2008/05/02 04:15:14 mast Exp $
+|| $Id: pike_types.c,v 1.324 2008/05/03 20:06:07 grubba Exp $
 */
 
 #include "global.h"
@@ -3683,6 +3683,7 @@ static int low_pike_types_le2(struct pike_type *a, struct pike_type *b,
 			      int array_cnt, unsigned int flags)
 #endif /* PIKE_TYPE_DEBUG */
 {
+  struct compilation *c = MAYBE_THIS_COMPILATION;
   int ret;
 
  recurse:
@@ -3751,29 +3752,23 @@ static int low_pike_types_le2(struct pike_type *a, struct pike_type *b,
       b = b->cdr;
       goto recurse;
     }
-#if 0
-    if (!flags & LE_USE_HANDLERS) {
+    if (!c) {
       a = a->cdr;
       goto recurse;
     }
-#endif /* 0 */
     if (!low_pike_types_le(a->cdr, b, array_cnt, flags)) return 0;
-#if 0
     ref_push_string((struct pike_string *)a->car);
     ref_push_type_value(a->cdr);
     ref_push_type_value(b);
-    push_int(1);
-    if (safe_apply_handler("handle_attribute", error_handler, compat_handler,
-			   4, 0)) {
-      if ((Pike_sp[-1].type == T_INT) &&
-	  (Pike_sp[-1].subtype == NUMBER_NUMBER) &&
-	  (!Pike_sp[-1].u.integer)) {
-	pop_stack();
-	return 0;
-      }
+    safe_apply_current2(PC_POP_TYPE_ATTRIBUTE_FUN_NUM, 3,
+			"pop_type_attribute");
+    if ((Pike_sp[-1].type == T_INT) &&
+	(Pike_sp[-1].subtype == NUMBER_NUMBER) &&
+	(!Pike_sp[-1].u.integer)) {
       pop_stack();
+      return 0;
     }
-#endif /* 0 */
+    pop_stack();
     return 1;
 
   case T_NOT:
@@ -3909,29 +3904,23 @@ static int low_pike_types_le2(struct pike_type *a, struct pike_type *b,
     goto recurse;
 
   case PIKE_T_ATTRIBUTE:
-#if 0
-    if (!flags & LE_USE_HANDLERS) {
+    if (!c) {
       b = b->cdr;
       goto recurse;
     }
-#endif /* 0 */
     if (!low_pike_types_le(a, b->cdr, array_cnt, flags)) return 0;
-#if 0
     ref_push_string((struct pike_string *)b->car);
     ref_push_type_value(a);
     ref_push_type_value(b->cdr);
-    push_int(2);
-    if (safe_apply_handler("handle_attribute", error_handler, compat_handler,
-			   4, 0)) {
-      if ((Pike_sp[-1].type == T_INT) &&
-	  (Pike_sp[-1].subtype == NUMBER_NUMBER) &&
-	  (!Pike_sp[-1].u.integer)) {
-	pop_stack();
-	return 0;
-      }
+    safe_apply_current2(PC_PUSH_TYPE_ATTRIBUTE_FUN_NUM, 3,
+			"push_type_attribute");
+    if ((Pike_sp[-1].type == T_INT) &&
+	(Pike_sp[-1].subtype == NUMBER_NUMBER) &&
+	(!Pike_sp[-1].u.integer)) {
       pop_stack();
+      return 0;
     }
-#endif /* 0 */
+    pop_stack();
     return 1;
   case PIKE_T_SCOPE:
 #ifdef TYPE_GROUPING
diff --git a/src/program.c b/src/program.c
index 72858ca5b90f823b78ba9eae4a23044984fe5c0e..4299516b90bda8c85e9e341b058e5dc44c834c4e 100644
--- a/src/program.c
+++ b/src/program.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: program.c,v 1.685 2008/05/03 15:54:13 grubba Exp $
+|| $Id: program.c,v 1.686 2008/05/03 20:06:06 grubba Exp $
 */
 
 #include "global.h"
@@ -8393,6 +8393,100 @@ static void f_compilation_handle_inherit(INT32 args)
   }
 }
 
+/*! @decl int(0..1) pop_type_attribute(string attribute, @
+ *!                                    type a, type b)
+ *!
+ *!   Type attribute handler.
+ *!
+ *!   Called during type checking when @expr{a <= b@} and
+ *!   @[a] had the type attribute @[attribute] before the
+ *!   comparison.
+ *!
+ *!   The default implementation implements the "deprecated"
+ *!   attribute.
+ *!
+ *! @returns
+ *!   Returns @expr{1@} if the type check should be allowed
+ *!   (ie @expr{__attribute__(attribute, a) <= b@}), and
+ *!   @expr{0@} (zero) otherwise.
+ *!
+ *! @seealso
+ *!   @[push_type_attribute()]
+ */
+static void f_compilation_pop_type_attribute(INT32 args)
+{
+  struct pike_string *attr;
+  struct svalue *a, *b;
+  struct compilation *c = THIS_COMPILATION;
+  struct pike_string *deprecated_string;
+
+  get_all_args("pop_type_attribute", args, "%W%*%*", &attr, &a, &b);
+
+  if (Pike_compiler->compiler_pass == 2) {
+    MAKE_CONST_STRING(deprecated_string, "deprecated");
+    if (attr == deprecated_string) {
+      push_int(REPORT_WARNING);
+      ref_push_string(c->lex.current_file);
+      push_int(c->lex.current_line);
+      push_constant_text("type_check");
+      push_constant_text("Using deprecated %O value.");
+      push_svalue(a);
+      apply_current(PC_REPORT_FUN_NUM, 6);
+      args++;
+    }
+  }
+  pop_n_elems(args);
+  push_int(1);
+}
+
+/*! @decl int(0..1) push_type_attribute(string attribute, @
+ *!                                     type a, type b)
+ *!
+ *!   Type attribute handler.
+ *!
+ *!   Called during type checking when @expr{a <= b@} and
+ *!   @[b] had the type attribute @[attribute] before the
+ *!   comparison.
+ *!
+ *!   The default implementation implements the "deprecated"
+ *!   attribute.
+ *!
+ *! @returns
+ *!   Returns @expr{1@} if the type check should be allowed
+ *!   (ie @expr{a <= __attribute__(attribute, b)@}), and
+ *!   @expr{0@} (zero) otherwise.
+ *!
+ *! @seealso
+ *!   @[pop_type_attribute()]
+ */
+static void f_compilation_push_type_attribute(INT32 args)
+{
+  struct pike_string *attr;
+  struct svalue *a, *b;
+  struct compilation *c = THIS_COMPILATION;
+  struct pike_string *deprecated_string;
+
+  get_all_args("push_type_attribute", args, "%W%*%*", &attr, &a, &b);
+
+  if (Pike_compiler->compiler_pass == 2) {
+    MAKE_CONST_STRING(deprecated_string, "deprecated");
+    if (attr == deprecated_string &&
+	!((a->type == PIKE_T_TYPE) && (a->u.type == zero_type_string))) {
+      /* Don't warn about setting deprecated values to zero. */
+      push_int(REPORT_WARNING);
+      ref_push_string(c->lex.current_file);
+      push_int(c->lex.current_line);
+      push_constant_text("type_check");
+      push_constant_text("Using deprecated %O value.");
+      push_svalue(b);
+      apply_current(PC_REPORT_FUN_NUM, 6);
+      args++;
+    }
+  }
+  pop_n_elems(args);
+  push_int(1);
+}
+
 static void f_compilation__sprintf(INT32 args)
 {
   struct compilation *c = THIS_COMPILATION;
@@ -8664,6 +8758,12 @@ static void compile_compiler(void)
   ADD_FUNCTION("handle_inherit", f_compilation_handle_inherit,
 	       tFunc(tStr, tPrg(tObj)), 0);
 
+  ADD_FUNCTION("pop_type_attribute", f_compilation_pop_type_attribute,
+	       tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);
+
+  ADD_FUNCTION("push_type_attribute", f_compilation_push_type_attribute,
+	       tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);
+
   ADD_FUNCTION("_sprintf", f_compilation__sprintf,
 	       tFunc(tInt tOr(tMap(tStr, tMix), tVoid), tStr), ID_STATIC);
 
diff --git a/src/testsuite.in b/src/testsuite.in
index 00b9687f1a86eee758ed82421d064c168ca817f6..753b192c35d8fc85c915632c117bce06377b3436 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -1,5 +1,5 @@
 START_MARKER
-test_true([["$Id: testsuite.in,v 1.803 2008/05/03 15:51:50 grubba Exp $"]]);
+test_true([["$Id: testsuite.in,v 1.804 2008/05/03 20:06:07 grubba Exp $"]]);
 
 // This triggered a bug only if run sufficiently early.
 test_compile_any([[#pike 7.2]])
@@ -11131,6 +11131,39 @@ test_compile_error_any(class A {nomask int f(){}} class B {inherit A; int f;})
 test_compile_any(class A {local int f(){}} class B {inherit A; int f;})
 test_compile_any(class A {inline int f(){}} class B {inherit A; int f;})
 
+// - attributes
+test_compile_any(
+  class A { __deprecated__ int foo(int x) { return x; } };
+)
+test_compile_warning(
+  class A { __deprecated__ int foo(int x) { return x; } };
+  A()->foo(0);
+)
+test_compile_warning(
+  class A { __deprecated__ int foo(int x) { return x; } };
+  function bar = A()->foo;
+)
+test_compile_warning(
+  class A { __deprecated__(int) foo(int x) { return x; } };
+)
+test_compile_any(
+  class A { __deprecated__(int) foo(int x) { return (__deprecated__(int))x; } };
+)
+test_compile_warning(
+  class A { int foo(__deprecated__(int)|void x) { return x; } };
+)
+test_compile_warning(
+  class A { int foo(__deprecated__(int)|void x) { return (int)x; } };
+)
+test_compile_warning(
+  class A { int foo(__deprecated__(int)|void x) { return (int)x; } };
+  A()->foo(0);
+)
+test_compile_any(
+  class A { int foo(__deprecated__(int)|void x) { return (int)x; } };
+  A()->foo();
+)
+
 // - modifiers, compile time access properties
 
 test_compile_error_any(class A {} class B {inherit A; int q; void g(){q=v;}})