Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AST] AutoType within AutoTypeLoc is missing deduced type. #42259

Open
sam-mccall opened this issue Aug 7, 2019 · 5 comments
Open

[AST] AutoType within AutoTypeLoc is missing deduced type. #42259

sam-mccall opened this issue Aug 7, 2019 · 5 comments
Labels
bugzilla Issues migrated from bugzilla clang Clang issues not falling into any other category

Comments

@sam-mccall
Copy link
Collaborator

Bugzilla Link 42914
Version trunk
OS Linux
CC @gislan,@mizvekov,@zygoloid,@HighCommander4

Extended Description

the program auto x = 4; has an AST that looks like:

VarDecl type=T1

  • typeloc type=T2
  • integerliteral

T1 is correctly an auto type that wraps int.
However T2 is undeduced: it's ASTContext::getAutoDeductType().

This irregularity makes it harder/slower to write tools that (e.g.) care what an auto under the cursor expands to.

@HighCommander4
Copy link
Collaborator

I investigated this a bit. What seems to be happening is:

  • At the time the VarDecl node is created, we haven't seen the
    initializer (and thus computed the deduced type) yet, so
    we set the VarDecl's type to an empty DeducedType. The
    TypeSourceInfo stored in the DeclaratorDecl is set based on
    this as well.

  • Later, we encounter the initializer and compute the deduced
    type. This happens in Sema::DeduceVariableDeclarationType().

  • We update the deduced type on the VarDecl via
    ValueDecl::setType() [1]. This updates ValueDecl::DeclType,
    but it does not update DeclaratorDecl::DeclInfo, which
    continues to point to the TypeSourceInfo wrapping the old,
    empty DeducedType.

  • When RecursiveASTVisitor (which is what clangd uses to
    get at the TypeLoc) encounters a DeclaratorDecl, it prefers
    to get the TypeLoc via the TypeSourceInfo if there is one [2],
    only falling back to ValueDecl::DeclType otherwise.
    Therefore, it gives us the undeduced, empty TypeLoc.

[1]

VDecl->setType(DeducedType);

[2]
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));

@HighCommander4
Copy link
Collaborator

Naively, I would think the solution ought to be that, in addition to calling VDecl->setType(), Sema::DeduceVariableDeclarationType() should also call VDecl->setTypeSourceInfo().

However, I don't at this stage understand how these types (Type / TypeLoc / TypeSourceInfo) interact well enough to know how to construct a TypeSourceInfo in that place.

@sam-mccall
Copy link
Collaborator Author

I heard that Ilya Biryukov and Richard Smith had a conversation about this bug, and it wasn't totally trivial.
But I'm not sure that was written down anywhere, it'd be good to get Richard's take (even if second-hand) on what needs to happen here.

@zygoloid
Copy link
Mannequin

zygoloid mannequin commented Jan 10, 2020

A couple of issues:

  1. For functions with deduced return types, it's important that the AST representation for the TypeSourceInfo does not contain the deduced type. Redeclaration matching requires that we preserve the non-deduced auto in the declared return type. So tooling that wants to inspect auto types needs to be able to look into the type, not just the type source info, in general.

  2. For variables with deduced types, it's important to serialization that we don't include the deduced type in the type source info. We load the type source info early (before merging), and doing so must not deserialize (say) a lambda used to initialize the variable, because that would introduce a deserialization cycle. We could perhaps avoid that for variables, by removing the type-checks we perform when merging declarations of variables across modules (those checks are strictly-speaking wrong anyway, since they mean we won't merge 'extern int n;' with 'auto n = 0;').

So, I think we could change our model so that we store the deduced type in the TypeSourceInfo of a variable. It would require some contortions in deserialization, and perhaps elsewhere. But I don't think we want to change our model for functions, where it's important that we preserve the declared type. So far, the consistency argument (the TypeSourceInfo should always represent the declared type) has won out over the convenience-for-tooling argument, especially given that tooling will need to deal with the deduced-type-is-not-in-the-TSI case anyway to properly handle functions with deduced return types. But perhaps someone can come up with a smart design that gives us the best of both worlds (perhaps we could represent the auto type in the TSI as a type that is canonically an undeduced auto but that tracks the deduced type via some type sugar?)

@HighCommander4
Copy link
Collaborator

especially given that tooling will need to deal with the
deduced-type-is-not-in-the-TSI case anyway to properly handle functions
with deduced return types.

Note, it's RecursiveASTVisitor that ignores the type and visits the TSI in the case where we have a TSI.

Would it be reasonable to change the behaviour of RecursiveASTVisitor here? The actual tooling use cases (at least, the ones we've come across in clangd that I'm aware of) should "just work" if RAV visited the deduced type.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla clang Clang issues not falling into any other category
Projects
None yet
Development

No branches or pull requests

2 participants