This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Contents of Wei Dai's Crypto23.Zip - Segmentation fault with verification process


On May 29,  9:39pm, Roberto Bagnara wrote:
} Subject: Re: Contents of Wei Dai's Crypto23.Zip - Segmentation fault with 

> Reading 12.4 I understand that the fragment
> 
>   void foo(I* p)
>   {
>     p->I::~I();
>   }
> 
> should be ok whatever type I is. (Point 15 in 12.4 specifies that it
> works also for scalar types, e.g., typedef int I.)

> However, if I define
> 
> typedef C I;
> 
> class C {
> public:
> 	int i;
> };
> 
> bugrep1.cc: In function `void foo(class I *)':
> bugrep1.cc:53: qualified type `C' does not match destructor name `~I'

Roberto,

I believe the way to express this is:

class C;

typedef C I;

void foo(I* p)
{
	p->~I();
}


[ The following quotes are from the December 96 draft standara.d ]
  
In fact, the syntax you attempting to use is expressly prohibited in
Section 12.4 point 12:

12In  an  explicit  destructor  call, the destructor name appears as a ~
  followed by a type-name that names the destructor's class  type.   The
  invocation  of  a  destructor is subject to the usual rules for member
  functions (_class.mfct_), that  is,  if  the  object  is  not  of  the
  destructor's class type and not of class derived from the destructor's
  class type, the program has undefined behavior (except  that  invoking
  delete on a null pointer has no effect).  [Example:
          struct B {
                  virtual ~B() { }
          };
          struct D : B {
                  ~D() { }
          };
          D D_object;
          typedef B B_alias;
          B* B_ptr = &D_object;
          D_object.B::~B();     // calls B's destructor
          B_ptr->~B();          // calls D's destructor
          B_ptr->~B_alias();    // calls D's destructor
          B_ptr->B_alias::~B(); // calls B's destructor
          B_ptr->B_alias::~B_alias(); // error, no B_alias in class B
   --end example]

The syntax you are attempting is the last in the list of examples.

So, you can use

	p->~I();
or
	p->I::~C();

This rule makes sense, creating a typedef for a class does not change
the name of any of the functions in the class, including the constructors
and destructors.  This rule applies everywhere, from Section 12.4 point 1:

1 A  special  declarator  syntax  using  an  optional function-specifier
  (_dcl.fct.spec_) followed by ~ followed by the destructor's class name
  followed  by an empty parameter list is used to declare the destructor
  in a class definition.  In such a declaration, the ~ followed  by  the
  destructor's  class name can be enclosed in optional parentheses; such
  parentheses are ignored.  A typedef-name  that  names  a  class  is  a
  class-name (_dcl.typedef_); however, a typedef-name that names a class
  shall not be used as the identifier in the declarator for a destructor
  declaration.

Note the last sentence, although it is talking about the declarator here
and therefore does not apply directly to your test case it shows that
the rule is applied consistently to user-defined types.

However this rule does not apply to scalar types, which seems silly
to me.  From section 12.4 point 15:

15[Note:  the notation for explicit call of a destructor can be used for
  any scalar type name (_expr.pseudo_).  Allowing this makes it possible
  to  write  code  without  having  to know if a destructor exists for a
  given type. For example,

          typedef int I;
          I* p;
          // ...
          p->I::~I();

This means that

	p->I::~I();

is correct if I is a type-name for a scalar type, and incorrect if it is
a type-name for a user defined type.  Furthermore, it does not seem clear
if:

	p->~I();

is valid for scalar types, which would imply that you would need to know
if I is a typedef for a scalar or user-defined type to write correct code.
Section 5.2.4:

  5.2.4  Pseudo destructor call                            [expr.pseudo]

1 The use of a pseudo-destructor-name after a dot .  or arrow ->  opera-
  tor  represents  the  destructor for the non-class type named by type-
  name.  The result shall only be used as the operand for  the  function
  call  operator  (),  and the result of such a call has type void.  The
  only effect is the evaluation of the postfix-expression before the dot
  or arrow.

2 The  left  hand side of the dot operator shall be of scalar type.  The
  left hand side of the arrow operator shall be  of  pointer  to  scalar
  type.   This  scalar  type is the object type.  The type designated by
  the pseudo-destructor-name shall be the same as the object type.  Fur-
  thermore, the two type-names in a pseudo-destructor-name of the form
          ::opt nested-name-specifieropt type-name :: ~ type-name
  shall designate the same scalar type.

I'm going to ask about this on comp.std.c++, hopefully this wart was
cleared up in the FDIS.

Regards,

Niall


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]