From: Dave Rolsky Date: Sun, 21 Jun 2009 16:14:09 +0000 (-0500) Subject: Make sure we always local-ize $@ and $SIG{__DIE__} for code evals. X-Git-Tag: 0.87~5 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FClass-MOP.git;a=commitdiff_plain;h=e24b19fbbf5a62172dad0d8dfb86e03eed9a51c1 Make sure we always local-ize $@ and $SIG{__DIE__} for code evals. This required some changes to the CMOP::Method::Inlined API which propogated out to anything that calls ->_eval_closure. --- diff --git a/lib/Class/MOP/Class.pm b/lib/Class/MOP/Class.pm index ecfe5b2..d9f903b 100644 --- a/lib/Class/MOP/Class.pm +++ b/lib/Class/MOP/Class.pm @@ -623,7 +623,7 @@ sub add_method { my ( $current_package, $current_name ) = Class::MOP::get_code_info($body); - if ( $current_name eq '__ANON__' ) { + if ( !defined $current_name || $current_name eq '__ANON__' ) { my $full_method_name = ($self->name . '::' . $method_name); subname($full_method_name => $body); } diff --git a/lib/Class/MOP/Method/Accessor.pm b/lib/Class/MOP/Method/Accessor.pm index 1f71913..40b5ec7 100644 --- a/lib/Class/MOP/Method/Accessor.pm +++ b/lib/Class/MOP/Method/Accessor.pm @@ -159,7 +159,7 @@ sub _generate_accessor_method_inline { my $attr_name = $attr->name; my $meta_instance = $attr->associated_class->instance_metaclass; - my $code = $self->_eval_closure( + my ( $code, $e ) = $self->_eval_closure( {}, 'sub {' . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]') @@ -167,7 +167,7 @@ sub _generate_accessor_method_inline { . $meta_instance->inline_get_slot_value('$_[0]', $attr_name) . '}' ); - confess "Could not generate inline accessor because : $@" if $@; + confess "Could not generate inline accessor because : $e" if $e; return $code; } @@ -184,14 +184,14 @@ sub _generate_reader_method_inline { my $attr_name = $attr->name; my $meta_instance = $attr->associated_class->instance_metaclass; - my $code = $self->_eval_closure( + my ( $code, $e ) = $self->_eval_closure( {}, 'sub {' . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;' . $meta_instance->inline_get_slot_value('$_[0]', $attr_name) . '}' ); - confess "Could not generate inline reader because : $@" if $@; + confess "Could not generate inline reader because : $e" if $e; return $code; } @@ -208,13 +208,13 @@ sub _generate_writer_method_inline { my $attr_name = $attr->name; my $meta_instance = $attr->associated_class->instance_metaclass; - my $code = $self->_eval_closure( + my ( $code, $e ) = $self->_eval_closure( {}, 'sub {' . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]') . '}' ); - confess "Could not generate inline writer because : $@" if $@; + confess "Could not generate inline writer because : $e" if $e; return $code; } @@ -231,13 +231,13 @@ sub _generate_predicate_method_inline { my $attr_name = $attr->name; my $meta_instance = $attr->associated_class->instance_metaclass; - my $code = $self->_eval_closure( + my ( $code, $e ) = $self->_eval_closure( {}, 'sub {' . $meta_instance->inline_is_slot_initialized('$_[0]', $attr_name) . '}' ); - confess "Could not generate inline predicate because : $@" if $@; + confess "Could not generate inline predicate because : $e" if $e; return $code; } @@ -254,13 +254,13 @@ sub _generate_clearer_method_inline { my $attr_name = $attr->name; my $meta_instance = $attr->associated_class->instance_metaclass; - my $code = $self->_eval_closure( + my ( $code, $e ) = $self->_eval_closure( {}, 'sub {' . $meta_instance->inline_deinitialize_slot('$_[0]', $attr_name) . '}' ); - confess "Could not generate inline clearer because : $@" if $@; + confess "Could not generate inline clearer because : $e" if $e; return $code; } diff --git a/lib/Class/MOP/Method/Constructor.pm b/lib/Class/MOP/Method/Constructor.pm index 14a3c80..c30e0f4 100644 --- a/lib/Class/MOP/Method/Constructor.pm +++ b/lib/Class/MOP/Method/Constructor.pm @@ -136,11 +136,11 @@ sub _generate_constructor_method_inline { $source .= ";\n" . '}'; warn $source if $self->options->{debug}; - my $code = $self->_eval_closure( + my ( $code, $e ) = $self->_eval_closure( $close_over, $source ); - confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$@" if $@; + confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$e" if $e; return $code; } diff --git a/lib/Class/MOP/Method/Generated.pm b/lib/Class/MOP/Method/Generated.pm index 5af96b8..ea0ea2c 100644 --- a/lib/Class/MOP/Method/Generated.pm +++ b/lib/Class/MOP/Method/Generated.pm @@ -29,22 +29,29 @@ sub _initialize_body { sub _eval_closure { # my ($self, $captures, $sub_body) = @_; my $__captures = $_[1]; - eval join( - "\n", - ( + + my $code; + + my $e = do { + local $@; + local $SIG{__DIE__}; + $code = eval join + "\n", ( map { /^([\@\%\$])/ or die "capture key should start with \@, \% or \$: $_"; - q[my ] - . $_ . q[ = ] - . $1 - . q[{$__captures->{'] - . $_ - . q['}};]; - } keys %$__captures - ), - $_[2] - ); + q[my ] + . $_ . q[ = ] + . $1 + . q[{$__captures->{'] + . $_ . q['}};]; + } keys %$__captures + ), + $_[2]; + $@; + }; + + return ( $code, $e ); } sub _add_line_directive { diff --git a/t/310_inline_structor.t b/t/310_inline_structor.t index bbdcce8..efceb2f 100644 --- a/t/310_inline_structor.t +++ b/t/310_inline_structor.t @@ -202,13 +202,15 @@ use Class::MOP; sub _inline_destructor { my $self = shift; - my $code = $self->_eval_closure( {}, 'sub { }' ); + my ( $code, $e ) = $self->_eval_closure( {}, 'sub { }' ); + die $e if $e; $self->{body} = $code; } sub is_needed { 1 } sub associated_metaclass { $_[0]->{metaclass} } + sub body { $_[0]->{body} } sub _expected_method_class { 'Base::Class' } } diff --git a/t/311_inline_and_dollar_at.t b/t/311_inline_and_dollar_at.t new file mode 100644 index 0000000..c1fc286 --- /dev/null +++ b/t/311_inline_and_dollar_at.t @@ -0,0 +1,21 @@ +use strict; +use warnings; + +use Test::More; + +plan tests => 1; + +use Class::MOP; + + +{ + package Foo; + + my $meta = Class::MOP::Class->initialize(__PACKAGE__); + + $@ = 'dollar at'; + + $meta->make_immutable; + + ::is( $@, 'dollar at', '$@ is untouched after immutablization' ); +}