mgehre marked an inline comment as done.
mgehre added inline comments.

================
Comment at: 
clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp:311
+  // This member function must stay non-const, even though
+  // it only calls other private const member functions.
+  int &get() {
----------------
gribozavr wrote:
> Is it because the const version already exists? Then that should be the rule 
> (not calling a private helper function).
Let me try to explain. If it make senses what I say, I'll then update the 
documentation.
The terms logical const and physical const are from here: 
https://isocpp.org/wiki/faq/const-correctness#logical-vs-physical-const

The const version is just here to illustrate how this pattern works. The 
important fact is that a private member function is not part of the public 
interface of the class. 
I.e. users of the class were not able to call `data()` with a const object 
before (even though data() is declared as const) because `data()` is at the 
same time `private`.
We thus cannot assume that the `constness` of `data()` reflects the interface 
contract the the author of the class had in mind.

Here, e.g. the author clearly wanted to only give access to a non-const `int&` 
to users that possses a non-const version of *this.

The rule "don't make the method const if it already has a const overload" seems 
appealing, but its neither sufficient (we still need the rule we currently have 
about private data)
nor is is necessary once we have all other rules. I have successfully run this 
check on the LLVM code base, and there were not issues with clashing overloads 
after fix-its. (It found multiple hundred of valid fixits)

The second example how to see the issue with private data members is the Pimpl 
idiom:
```
class S {
  struct Impl {
   int d;
  };
  Impl *I;
public:
  void set(int v) {
    I->d = v;
  }
};
```
A human would not make the `set()` function const because we consider the value 
of `Impl->d` to be part of the value of the instance. Technically, we can make 
`set()` const because
it does not modify `I`. But that is not the author's intention. I try to have 
no false-positives in this check,
so I conservatively assume that an access to a private member that is not of 
builtin type does not preserve logical constness.
Note that the same happens when the type of I is changed to `unique_ptr<Impl>`. 
`unique_ptr::operator->` is a const member function but returns a reference to 
non-const `Impl`,
and so does not preserve logical constness

We might be able to extend the check by tracking pointer use, but that's pretty 
difficult.
The only extension I did is for builtin types, i.e.`int`. When we read an int 
(in the AST that's an LvalueToRvalue conversion), then there is no way that 
this can eventually lead to a modification
of the state of the int, so it preserves logical constness.

Const use of public members is also ok because the user of the class already 
has access to them. We are not widening the contract by making a member 
function const that
(only) contains const use of public members.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68074/new/

https://reviews.llvm.org/D68074



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to