This is an archive of the discontinued LLVM Phabricator instance.

PR28752: Do not instantiate var decls which are not visible.
ClosedPublic

Authored by v.g.vassilev on Sep 13 2016, 7:40 AM.

Details

Reviewers
rsmith

Diff Detail

Event Timeline

v.g.vassilev retitled this revision from to PR28752: Do not instantiate var decls which are not visible..
v.g.vassilev updated this object.
v.g.vassilev added a reviewer: rsmith.
v.g.vassilev set the repository for this revision to rL LLVM.
v.g.vassilev added a subscriber: cfe-commits.
rsmith edited edge metadata.Sep 13 2016, 2:04 PM

I expect this patch to cause problems if the two definitions of the variable template come from different modules, because at deserialization time we don't merge the definitions together sensibly (it looks like we end up with a redeclaration chain with multiple declarations, multiple of which believe they are "the" defintiion).

lib/Sema/SemaTemplate.cpp
470

|| on the previous line, please.

472–476

Variable names should start with a capital letter.

478

We'll need to extend hasVisibleDefinition to handle merged VarDecls to support this. (The ASTReader doesn't currently merge together VarDecl definitions in a reasonable way.)

512–513

else if doesn't make sense here -- we either need to produce a diagnostic on all paths through here, or suppress the notes if we didn't produce a diagnostic.

530

Likewise here.

v.g.vassilev edited edge metadata.
v.g.vassilev removed rL LLVM as the repository for this revision.
v.g.vassilev marked 4 inline comments as done.

Address comments.

I still find the regression test a bit clumsy. I will try to add it to test/Modules/submodules-merge-defs.cpp, would this be the right place for it?

I think you'll also need to update the ASTDeclReader to merge VarDecl definitions together if it reads a definition and there already is one in the AST. I note that right now Sema::AddInitializerToDecl permits multiple definitions of a VarDecl, which doesn't seem like what we want here; we'll probably want to merge those as we parse them, too.

Now, we have a problem here: unlike with classes and functions, we can't always convert a variable definition to a declaration by just dropping the initializer. Perhaps we can add a flag to VarDecl to indicate "this is just a declaration, even though it looks like a definition", to handle that case? (This would also be useful for VarTemplateSpecializationDecls, where we currently reject valid code such as "template<typename> int n; int k = n<int>;" because we have no way to represent the difference between a mere declaration and a definition of n<int>.)

lib/Sema/SemaTemplate.cpp
505

Why do we not issue a diagnostic in this case for a VarDecl when Complain is true and no definition is available? It seems like we should either be diagnosing this or asserting that it can't happen.

530

else + assert would make more sense here. No other kind of declaration should get here.

lib/Sema/SemaType.cpp
6904–6905

We should add a getTemplateInstantiationPattern() to VarDecl and use it from here.

Address some comments and publish current progress.

rsmith added a comment.Oct 5 2016, 2:08 PM

This looks like it's going in the right direction.

lib/AST/Decl.cpp
2269–2272

I think we need a similar check in the static data member case above.

2278

enum?

lib/Sema/SemaTemplate.cpp
512–513

This function still appears to be able to return true (indicating to the caller that a diagnostic was produced) without actually producing a diagnostic.

lib/Serialization/ASTWriterDecl.cpp
896–897

Sink this flag into the "not for ParmVarDecl" block below.

1962

Hmm. The width of the InitStyle field is definitely wrong right now, but should be fixed separately from this change. It looks like we don't hit this today because we don't use this abbreviation for a variable with an initializer. In addition to fixing the width of this field, we should also remove the getInit() == nullptr check when selecting the abbreviation in ASTDeclWriter::VisitVarDecl.

v.g.vassilev marked 4 inline comments as done.

Rebase, comments some more fixes.

v.g.vassilev added inline comments.Oct 6 2016, 8:45 AM
lib/Sema/SemaTemplate.cpp
505

I believe it is not implemented, i.e. we didn't have this diagnostics when VarDecl::getInstantiatedFromStaticDataMember is true. I added a FIXME: for a future enhancement.

512–513

Is it better now?

lib/Serialization/ASTWriterDecl.cpp
896–897

I thought we might need this for c-style void f(struct S arg)-like constructs where we might need to demote if we merge ParmVarDecls.

1962

Committed in r283444.

rsmith added inline comments.Oct 6 2016, 2:11 PM
lib/Sema/SemaDecl.cpp
3692–3693

We always get here after calling that, don't we? So we only briefly have two definitions, between the point at which we attach the definition and now. If that's what you're referring to here, this comment could be clearer about it.

3695

You should also call makeMergedDefinitionVisible(Def, New->getLocation()) here (and also call it for Def's enclosing template if this is a variable template definition) to make the prior definition visible.

lib/Serialization/ASTReaderDecl.cpp
3083–3087

I don't think this is worthwhile, since it's the first thing the loop below will check.

3089

You should start at PrevVD not at D->First. This loop will currently only iterate once.

3090

You can also bail out early and demote the current definition if you reach a previous demoted definition. That would reduce this from quadratic-time to linear-time.

lib/Serialization/ASTWriterDecl.cpp
896–897

We'll still have only one ParmVarDecl per FunctionDecl, and no-one cares whether a ParmVarDecl is a definition. Also, you assert that the flag is always false in this case below.

v.g.vassilev marked 3 inline comments as done.

Address comments.

v.g.vassilev marked 5 inline comments as done.Oct 10 2016, 8:17 AM
rsmith accepted this revision.Oct 10 2016, 3:48 PM
rsmith edited edge metadata.
rsmith added inline comments.
include/clang/AST/Decl.h
1222

You can remove this; it's covered by the next line.

lib/AST/Decl.cpp
2284

Missing a member specialization check here.

lib/Serialization/ASTReaderDecl.cpp
3086–3090

Maybe combine these two ifs into one, since their bodies are identical?

This revision is now accepted and ready to land.Oct 10 2016, 3:48 PM
v.g.vassilev marked 2 inline comments as done.Oct 11 2016, 7:06 AM

Landed in r283882.

include/clang/AST/Decl.h
1222

Ok. This would allow calling the method on already demoted definition. Do we want to allow that?

lib/AST/Decl.cpp
2284

Isn't that covered by the cases above? It seems there is no API to make such check, here. The current state looks to me consistent with CXXRecordDecl::getTemplateInstantiationPattern and FunctionDecl::getTemplateInstantiationPattern.

lib/Serialization/ASTReaderDecl.cpp
3086–3090

Good point ;)

rsmith added inline comments.Oct 11 2016, 2:33 PM
include/clang/AST/Decl.h
1213

This is the bug. You can't read this bit here without first checking whether you are a ParmVarDecl, because ParmVarDecls don't have this bit at all.

1222

Demoted definitions return false from isThisDeclarationADefinition(), so the next line catches this case.

v.g.vassilev edited edge metadata.
v.g.vassilev marked 2 inline comments as done.

We should not access the IsThisDeclarationADemotedDefinition bits if the decl is ParmVarDecl.

v.g.vassilev closed this revision.Oct 12 2016, 5:30 AM
v.g.vassilev marked an inline comment as done.

Relanded in r284008.

I reverted this in r284081, and relanded with fixes described here as r284284.

lib/Sema/SemaDecl.cpp
9712

We also need to do this work when MergeVarDecls encounters the same condition.

lib/Serialization/ASTReaderDecl.cpp
3087

When we do this, we need to tell the ASTContext we merged the definitions, so that the old definition will be made visible whenever the new one is.