This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Re: Contents of Wei Dai's Crypto23.Zip - Segmentation fault with verification process
- To: Roberto Bagnara <bagnara at di dot unipi dot it>, law at cygnus dot com
- Subject: Re: Contents of Wei Dai's Crypto23.Zip - Segmentation fault with verification process
- From: njs3 at doc dot ic dot ac dot uk (Niall Smart)
- Date: Sat, 30 May 1998 11:33:07 +0100
- Cc: egcs-bugs at cygnus dot com
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