[llvm-dev] RFC: Modernizing our use of auto

Stephen Kelly via llvm-dev llvm-dev at lists.llvm.org
Sun Nov 25 06:43:15 PST 2018


I'm not advocating AAA.

However this is a proposal for more modern thinking regarding the 
permissiveness of auto in LLVM codebases.

Currently the rule on the use of auto is here:

 
https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable

It is quite strict. It allows the use of auto for

* lambdas
* iterators because they are long to type
* casts to the type

but generally leaves the rest up to the reviewer, not the contributor.

The notes about "more readable", "easier to maintain", "obvious from the 
context" are very subjective.

I think these guidelines need to be made more clear both in that 
subjective sense, but also in the sense of use of new/recent language 
and library features, given that LLVM will allow C++17 features in a few 
months. For example:

* Can we use auto in the initializer of range-for statements?
* Can we use auto in the initializer of if() statements?
* Can we use auto with llvm:Optional instances?
* Can we use auto in c++14 lambda arguments with llvm::find_if(C, 
[](const auto& i) { ... }) for example?
* We need to use auto for structured bindings, if those are used.

I know some people are very opposed to use of auto except in exceptional 
circumstances, but

* Some features force it a bit
* Elsewhere it is becoming more common for it to be reasonable to use. 
People are not  going as far as AAA, but auto is generally used in 
blogs, slides, and other peoples code (eg 
https://skebanga.github.io/if-with-initializer/). It's becoming more 
normalized without becoming extreme.
* Our potential contributors will not see a problem with using it in the 
above cases

So, we might benefit from somewhat more-modern guidelines.

Reviewers are very subjective and that means it is hard to predict what 
the requirements will be, depending on the reviewer. This is confusing 
for contributors.

For example, I was told by a reviewer that auto should *not* be used in 
the initalizer of a range for loop.  However, even the next section of 
the coding guidelines suggest that is ok:

 
https://llvm.org/docs/CodingStandards.html#beware-unnecessary-copies-with-auto

So, perhaps the guidelines for reviewers needs to adapt, or the coding 
guidelines need to adapt.

Currently, reviewers reject code of the form

   void foo()
   {
     auto ParserInstance = Parser::getFromArgs(Args);
     if (ParserInstance)
       obj.someApi(ParserInstance);
   }

as unreadable while

   void foo()
   {
     obj.otherApi(Parser::getFromArgs(Args));
   }

is fine. It would be good to have an answer in the coding guidelines to 
whether

   void foo()
   {
     if (auto ParserInstance = Parser::getFromArgs(Args); ParserInstance)
       obj.someApi(ParserInstance);
   }

is ok or not.

In the case that came up in review for me, the code I submitted is

template <typename BaseT, typename DerivedT>
void registerIfNodeMatcher(...) {
   auto NodeKind = ASTNodeKind::getFromNodeKind<DerivedT>();
   if (!NodeKind.isNone())
     NodeCtors[NodeKind] = std::make_pair(MatcherName, Descriptor);
}

but it was rejected as unreadable and I was given a link to the coding 
guidelines.

'NodeKind' appears three times in one line in that code and the 
requirement is to add it again. ASTNodeKind is a very commonly used 
class in that part of Clang, so it should be familiar enough. We only 
need the local variable at all so that we can do a validity check. There 
is no reasonable need to put the type there or even to care what exactly 
the type is. All we need to know is that we check the validity of the 
instance before using it.

I'd like to update the coding guidelines so that code such as

void foo(...) {
   auto Bar = SomeAPI();
   if (/* validity condition */)
     OtherAPI(Bar);
}

is unambiguously acceptable in the coding guidelines.

That kind of thing is coming up as Optional is used more in the 
codebase, but also with objects which have a validity check such as 
isNone(), isValid(), isNull() or just `!= nullptr` etc.

I'd also like to update them so that

llvm::Optional<std::pair<std::string, MatcherCtor>>
getNodeConstructorType(ASTNodeKind targetType) {
   auto const &ctors = RegistryData->nodeConstructors();
   auto it = llvm::find_if(
       ctors, [targetType](const NodeConstructorMap::value_type &ctor) {
         return ctor.first.isSame(targetType);
       });
   if (it == ctors.end())
     return llvm::None;
   return it->second;
}

is acceptable. The `auto it` is already acceptable, but the `auto const& 
ctors` depends on an interpretation of the guideline and was rejected in 
the review I submitted.

In that code, we only create the local `ctors` variable because we need 
to compare the `end` iterator after the algorithm.  If auto is ok to use 
in range-for loops, then reasonably it should be ok in the above code too.

Naturally, the guidelines should only be changed if there is consensus 
to change them. No one is trying to force anything, but I'm trying to 
address an inconsistency in reviews and a pain point for a new 
contributor. I'm trying to see if I can make the experience easier by 
updating the guidelines. Reviewers should be able to fall back to a good 
guideline, even if it differs from their subjective taste.

This is a pain point for me as a relatively new contributor to LLVM 
because sometimes reviewers have differing opinions. We shouldn't be 
putting up barriers to new contributors, but trying to remove them 
instead. I put up

  https://reviews.llvm.org/D54877

to try to start the conversation, so I'm interested in opinions!

Thanks,

Stephen.




More information about the llvm-dev mailing list