Bug 3396 – Compiler accepts call of superclass abstract method with no implementation

Status
RESOLVED
Resolution
FIXED
Severity
minor
Priority
P3
Component
dlang.org
Product
D
Version
D2
Platform
All
OS
All
Creation time
2009-10-14T02:20:30Z
Last change time
2023-10-11T23:18:34Z
Keywords
accepts-invalid, pull, spec
Assigned to
Walter Bright
Creator
anonymous4

Attachments

IDFilenameSummaryContent-TypeSize
1072test.dabstract methods not being flagged as unimplementedtext/x-dsrc94

Comments

Comment #0 by dfj1esp02 — 2009-10-14T02:20:30Z
--- abstract class A { abstract void M(); } class B:A { override void M(){ writeln("B.M"); super.M(); } } int main() { auto b=new B(); b.M(); return 0; } --- >dmd -c tmp.d -w -o- >dmd -w -run tmp.d OPTLINK (R) for Win32 Release 8.00.1 Copyright (C) Digital Mars 1989-2004 All rights reserved. tmp.obj(tmp) Error 42: Symbol Undefined _D3tmp1A1MMFZv --- errorlevel 1 Compilation with -o- passes successfully.
Comment #1 by rjmcguire — 2012-02-06T04:07:53Z
Created attachment 1072 abstract methods not being flagged as unimplemented I encountered this problem in a library, what I found interesting was that the program compiled and ran without crashing, just had empty output where I was expecting text. Attachment is a simpler test case with similar outcome: $ dmd test.d test.o:(.rodata+0xb0): undefined reference to `_D4test1A2a1MFZAya' collect2: ld returned 1 exit status --- errorlevel 1 $ dmd -c test.d $
Comment #2 by smjg — 2012-02-10T10:45:07Z
(In reply to comment #1) > Created an attachment (id=1072) [details] > abstract methods not being flagged as unimplemented AIUI a method declared without the abstract attribute is taken to reference a function defined elsewhere. Since no library or object file that defines such a function has been linked in, the linker errors. The original testcase is different: A.m is declared as abstract, so the compiler should reject the attempt to call it there and then.
Comment #3 by verylonglogin.reg — 2014-07-18T09:59:08Z
This is a documented and intended behavior. According to [1]: > Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide ‘base class functionality.’ It also maches C++ behavior with respect to pure virtual functions. An enhancement request to change it may be opened but this bug is invalid. [1] http://dlang.org/attribute.html#abstract
Comment #4 by smjg — 2014-07-18T17:57:42Z
(In reply to Denis Shelomovskij from comment #3) > This is a documented and intended behavior. According to [1]: >> Functions declared as abstract can still have function bodies. But A.M has no function body. So what's the relevance? >> This is so that even though they must be overridden, they can >> still provide ‘base class functionality.’ But no base class functionality has been provided. As such, the compiler cannot resolve the call to super.M and therefore should error. > It also maches C++ behavior with respect to pure virtual functions. What exactly does the C++ standard say about this? That said, is C++ behaviour relevant? D is not C++.
Comment #5 by yebblies — 2014-08-11T13:41:44Z
*** Issue 13278 has been marked as a duplicate of this issue. ***
Comment #6 by yebblies — 2014-08-11T13:48:00Z
This code: abstract class A { abstract void M(); } could mean one of two things: 1. M is a pure virtual function 2. M provides 'base class functionality', but this is a di file so the body isn't present. The compiler makes the conservative assumption 2, because it has no way to tell which was intended. A quick test makes it look like additionally marking the base class function with @disable makes it impossible to call without breaking inheritance.
Comment #7 by verylonglogin.reg — 2014-08-11T14:46:48Z
(In reply to yebblies from comment #6) > This code: > > abstract class A > { > abstract void M(); > } > > could mean one of two things: > 1. M is a pure virtual function > 2. M provides 'base class functionality', but this is a di file so the body > isn't present. You misuse terminology. "pure virtual function" is a C++ term which means "this function should be overriden to be able to instantiate class". There is no term for function that doesn't provide base class functionality. So D's 'abstract' means exactly what C++'s '=0' postfix does marking function "pure virtual" in contrast to e.g. C#'s 'abstract'.
Comment #8 by yebblies — 2014-08-11T15:05:45Z
(In reply to Denis Shelomovskij from comment #7) > (In reply to yebblies from comment #6) > > This code: > > > > abstract class A > > { > > abstract void M(); > > } > > > > could mean one of two things: > > 1. M is a pure virtual function > > 2. M provides 'base class functionality', but this is a di file so the body > > isn't present. > > You misuse terminology. "pure virtual function" is a C++ term which means > "this function should be overriden to be able to instantiate class". There > is no term for function that doesn't provide base class functionality. So > D's 'abstract' means exactly what C++'s '=0' postfix does marking function > "pure virtual" in contrast to e.g. C#'s 'abstract'. I figured people would understand what I meant. 1) is a function that has no implementation.
Comment #9 by blah38621 — 2014-08-11T16:22:17Z
Isn't it still reasonable for DMD to at least catch this error at compile-time rather than link-time if the module containing class A was passed on the command line, and thus is one of those being compiled, and not an interface?
Comment #10 by yebblies — 2014-08-11T17:04:44Z
(In reply to Orvid King from comment #9) > Isn't it still reasonable for DMD to at least catch this error at > compile-time > rather than link-time if the module containing class A was passed on the > command line, and thus is one of those being compiled, and not an interface? The compiler cannot tell the difference between d files and di files... And technically you're allowed to put the implementation in a library, implement it in asm, etc
Comment #11 by smjg — 2014-08-11T22:20:02Z
(In reply to Orvid King from comment #9) > Isn't it still reasonable for DMD to at least catch this error at > compile-time > rather than link-time if the module containing class A was passed on the > command line, and thus is one of those being compiled, and not an interface? This would break tools such as bud. (In reply to yebblies from comment #10) > The compiler cannot tell the difference between d files and di files... How do you mean, the compiler can't know the filename extension of the file passed into it?
Comment #12 by smjg — 2014-08-11T22:22:16Z
http://dlang.org/function.html "Functions without bodies: int foo(); that are not declared as abstract are expected to have their implementations elsewhere, and that implementation will be provided at the link step." Where does the spec indicate that functions that _are_ declared as abstract can also have their implementations elsewhere?
Comment #13 by yebblies — 2014-08-12T10:53:32Z
(In reply to Stewart Gordon from comment #11) > > The compiler cannot tell the difference between d files and di files... > > How do you mean, the compiler can't know the filename extension of the file > passed into it? It could, but it doesn't, and it shouldn't. d files and di files are the same thing to the compiler.
Comment #14 by yebblies — 2014-08-12T12:07:46Z
(In reply to Stewart Gordon from comment #12) > http://dlang.org/function.html > "Functions without bodies: > > int foo(); > > that are not declared as abstract are expected to have their implementations > elsewhere, and that implementation will be provided at the link step." > > Where does the spec indicate that functions that _are_ declared as abstract > can also have their implementations elsewhere? Where does it say that they can't?
Comment #15 by smjg — 2014-08-12T17:50:26Z
(In reply to yebblies from comment #14) > Where does it say that they can't? If such code is legal, the spec needs to explain its semantics somewhere.
Comment #16 by smjg — 2014-08-12T23:30:39Z
(In reply to yebblies from comment #6) > could mean one of two things: > 1. M is a pure virtual function > 2. M provides 'base class functionality', but this is a di file so the body > isn't present. Whether it's a di file or not, it could potentially be either. I'd be surprised if this ambiguity is a deliberate design decision. It also means that it's impossible to tell whether super.M() is a valid call just by reading the code. If I were designing it, I would define a way to distinguish them, such as requiring the extern attribute for meaning 2. Anyhow, we need clarification of this. At the moment there's nothing in the spec indicating that defining "base class functionality" of an abstract method elsewhere is meant to work. If it is meant to work, there needs to be. If it isn't, it is a bug that the compiler accepts the code. As such, I'm reopening this as a spec issue.
Comment #17 by dlang-bot — 2023-10-05T02:17:32Z
@SixthDot created dlang/dmd pull request #15652 "fix issue 3396 - call to unimplemented abstract method lead to linkin…" fixing this issue: - fix issue 3396 - call to unimplemented abstract method lead to linking error https://github.com/dlang/dmd/pull/15652
Comment #18 by dlang-bot — 2023-10-11T23:18:34Z
dlang/dmd pull request #15652 "fix issue 3396 - call to unimplemented abstract method lead to linkin…" was merged into master: - 275ce6d25826599cce5538161831cfd47fb038ae by Basile Burg: fix issue 3396 - call to unimplemented abstract method lead to linking error https://github.com/dlang/dmd/pull/15652