Hi Doug,
I’ve been working on using declarations a bit over the last week, amidst continued fire-fighting elsewhere, butI thought I’d better address some parts of it in pieces, rather than in a big unwieldy chunk. Rather than a patch, I’ll just list relevent pieces to discuss, as I have questions about the code. I hope it formats in a readable way here.
We’ll probably want to store more location information, e.g., the source range covering the nested-name-specifier, (e.g., “N:
:”), the source location of the target declaration’s name, and the source location of the “using” itself. Also, how about keeping track of the NestedNameSpecifier used to refer to the target declaration? It’s good for pretty-printing, and will also be needed when the using directive occurs within a template and the nested-name-specifier is dependent.
I was a litte fuzzy about the exact meaning of these, but here’s my best guess. First the new renamed UsingDecl:
/// UsingDecl - Represents C++ using-directive. For example:
/// using someNameSpace::someIdentifier;
class UsingDecl : public NamedDecl {
/// \brief The source range that covers the nested-name-specifier
/// preceding the namespace name.
SourceRange NestedNameRange;
/// \brief The source location of the target declaration name.
SourceLocation TargetNameLocation;
/// \brief The source location of the “using” location itself.
SourceLocation UsingLocation;
/// \brief Target declaration.
NamedDecl* TargetDecl;
/// \brief Target declaration.
NestedNameSpecifier* TargetNestedNameDecl;
// Had ‘typename’ keyword.
bool IsTypeName;
UsingDecl(DeclContext DC, SourceLocation L, SourceRange NNR,
SourceLocation TargetNL, SourceLocation UL, NamedDecl Target,
NestedNameSpecifier* TargetNNS, bool IsTypeNameArg)
: NamedDecl(Decl::Using, DC, L, Target->getDeclName()),
NestedNameRange(NNR), TargetNameLocation(TargetNL),
UsingLocation(UL), TargetDecl(Target),
TargetNestedNameDecl(TargetNNS), IsTypeName(IsTypeNameArg) { }
public:
/// \brief Returns the source range that covers the nested-name-specifier
/// preceding the namespace name.
SourceRange getNestedNameRange() { return(NestedNameRange); }
/// \brief Returns the source location of the target declaration name.
SourceLocation getTargetNameLocation() { return (TargetNameLocation); }
/// \brief Returns the source location of the “using” location itself.
SourceLocation getUsingLocation() { return(UsingLocation); }
/// \brief getTargetDecl - Returns target specified by using-decl.
NamedDecl getTargetDecl() { return(TargetDecl); }
/// \brief Get target nested name declaration.
NestedNameSpecifier getTargetNestedNameDecl() { return(TargetNestedNameDecl); }
/// \brief isTypeName - Return true if using decl had ‘typename’.
bool isTypeName() const { return(IsTypeName); }
static UsingDecl Create(ASTContext &C, DeclContext DC,
SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
SourceLocation UL, NamedDecl Target,
NestedNameSpecifier TargetNNS, bool IsTypeNameArg);
static bool classof(const Decl *D) {
return D->getKind() == Decl::Using;
}
static bool classof(const UsingDecl *D) { return true; }
};
Regarding the later comment:
Oh, and we might even consider storing the list of declarations that the using declaration refers to, because we need to model the semantics of paragraph 11:
The entity declared by a using-declaration shall be known in the context using it according to its definition
at the point of the using-declaration . Definitions added to the namespace after the using-declaration are not
considered when a use of the name is made.
I’m not sure what list of declarations is needed. If later definitions appear, it seems that a look up will find the using declaration first, and return the refered-to declaration. Or does this have something to do with overloading?
The additional source locations are handled in ActOnUsingDeclaration like:
UsingAlias = UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
NS->getLocation(), UsingLoc, NS,
static_cast<NestedNameSpecifier *>(SS.getScopeRep()),
IsTypeName);
Does this seem right?
Lastly, do you think Sema::LookupParsedName is the right place to do the substitution for non-redeclaration lookups? Or should it be lower in LookupName, with more conditions to exclude certain lookup types?
I’ll be experimenting with this next, as well as writing a bigger test, to ring out some of the trickier cases.
-John