Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- C++ -*-=//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the NestedNameSpecifier class, which represents
|
|
|
|
// a C++ nested-name-specifier.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/NestedNameSpecifier.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
2011-02-24 10:36:08 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2009-05-30 04:38:28 +08:00
|
|
|
#include "clang/AST/PrettyPrinter.h"
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2011-02-25 01:54:50 +08:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2012-08-15 09:41:43 +08:00
|
|
|
#include "llvm/Support/AlignOf.h"
|
2009-03-19 11:51:16 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2009-03-27 07:50:42 +08:00
|
|
|
#include <cassert>
|
2009-03-19 11:51:16 +08:00
|
|
|
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
NestedNameSpecifier *
|
2011-01-12 17:06:06 +08:00
|
|
|
NestedNameSpecifier::FindOrInsert(const ASTContext &Context,
|
2009-03-27 07:50:42 +08:00
|
|
|
const NestedNameSpecifier &Mockup) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
Mockup.Profile(ID);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
NestedNameSpecifier *NNS
|
2009-03-27 07:50:42 +08:00
|
|
|
= Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (!NNS) {
|
2012-08-15 09:41:43 +08:00
|
|
|
NNS = new (Context, llvm::alignOf<NestedNameSpecifier>())
|
|
|
|
NestedNameSpecifier(Mockup);
|
2009-03-27 07:50:42 +08:00
|
|
|
Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NNS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifier *
|
2011-01-12 17:06:06 +08:00
|
|
|
NestedNameSpecifier::Create(const ASTContext &Context,
|
|
|
|
NestedNameSpecifier *Prefix, IdentifierInfo *II) {
|
2009-03-27 07:50:42 +08:00
|
|
|
assert(II && "Identifier cannot be NULL");
|
2009-09-09 08:23:06 +08:00
|
|
|
assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");
|
2009-03-27 07:50:42 +08:00
|
|
|
|
|
|
|
NestedNameSpecifier Mockup;
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
2011-02-24 10:36:08 +08:00
|
|
|
Mockup.Prefix.setInt(StoredIdentifier);
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Specifier = II;
|
2009-03-27 07:50:42 +08:00
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifier *
|
2011-01-12 17:06:06 +08:00
|
|
|
NestedNameSpecifier::Create(const ASTContext &Context,
|
2013-01-24 01:06:56 +08:00
|
|
|
NestedNameSpecifier *Prefix,
|
|
|
|
const NamespaceDecl *NS) {
|
2009-03-27 07:50:42 +08:00
|
|
|
assert(NS && "Namespace cannot be NULL");
|
2009-09-09 23:08:12 +08:00
|
|
|
assert((!Prefix ||
|
2009-03-27 07:50:42 +08:00
|
|
|
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
|
|
|
|
"Broken nested name specifier");
|
|
|
|
NestedNameSpecifier Mockup;
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
2011-02-24 10:36:08 +08:00
|
|
|
Mockup.Prefix.setInt(StoredNamespaceOrAlias);
|
2013-01-24 01:06:56 +08:00
|
|
|
Mockup.Specifier = const_cast<NamespaceDecl *>(NS);
|
2009-03-27 07:50:42 +08:00
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
|
|
|
|
2011-02-24 10:36:08 +08:00
|
|
|
NestedNameSpecifier *
|
|
|
|
NestedNameSpecifier::Create(const ASTContext &Context,
|
|
|
|
NestedNameSpecifier *Prefix,
|
|
|
|
NamespaceAliasDecl *Alias) {
|
|
|
|
assert(Alias && "Namespace alias cannot be NULL");
|
|
|
|
assert((!Prefix ||
|
|
|
|
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
|
|
|
|
"Broken nested name specifier");
|
|
|
|
NestedNameSpecifier Mockup;
|
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
|
|
|
Mockup.Prefix.setInt(StoredNamespaceOrAlias);
|
|
|
|
Mockup.Specifier = Alias;
|
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
NestedNameSpecifier *
|
2011-01-12 17:06:06 +08:00
|
|
|
NestedNameSpecifier::Create(const ASTContext &Context,
|
|
|
|
NestedNameSpecifier *Prefix,
|
2011-01-19 14:33:43 +08:00
|
|
|
bool Template, const Type *T) {
|
2009-03-27 07:50:42 +08:00
|
|
|
assert(T && "Type cannot be NULL");
|
|
|
|
NestedNameSpecifier Mockup;
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
2011-02-24 10:36:08 +08:00
|
|
|
Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec);
|
2011-01-19 14:33:43 +08:00
|
|
|
Mockup.Specifier = const_cast<Type*>(T);
|
2009-03-27 07:50:42 +08:00
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
2009-09-03 07:58:38 +08:00
|
|
|
|
|
|
|
NestedNameSpecifier *
|
2011-01-12 17:06:06 +08:00
|
|
|
NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) {
|
2009-09-03 07:58:38 +08:00
|
|
|
assert(II && "Identifier cannot be NULL");
|
|
|
|
NestedNameSpecifier Mockup;
|
|
|
|
Mockup.Prefix.setPointer(0);
|
2011-02-24 10:36:08 +08:00
|
|
|
Mockup.Prefix.setInt(StoredIdentifier);
|
2009-09-03 07:58:38 +08:00
|
|
|
Mockup.Specifier = II;
|
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
|
|
|
|
2011-01-12 17:06:06 +08:00
|
|
|
NestedNameSpecifier *
|
|
|
|
NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
|
2009-03-27 07:50:42 +08:00
|
|
|
if (!Context.GlobalNestedNameSpecifier)
|
2012-08-15 09:41:43 +08:00
|
|
|
Context.GlobalNestedNameSpecifier =
|
|
|
|
new (Context, llvm::alignOf<NestedNameSpecifier>())
|
|
|
|
NestedNameSpecifier();
|
2009-03-27 07:50:42 +08:00
|
|
|
return Context.GlobalNestedNameSpecifier;
|
|
|
|
}
|
|
|
|
|
2011-02-24 10:36:08 +08:00
|
|
|
NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
|
|
|
|
if (Specifier == 0)
|
|
|
|
return Global;
|
|
|
|
|
|
|
|
switch (Prefix.getInt()) {
|
|
|
|
case StoredIdentifier:
|
|
|
|
return Identifier;
|
|
|
|
|
|
|
|
case StoredNamespaceOrAlias:
|
|
|
|
return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
|
|
|
|
: NamespaceAlias;
|
|
|
|
|
|
|
|
case StoredTypeSpec:
|
|
|
|
return TypeSpec;
|
|
|
|
|
|
|
|
case StoredTypeSpecWithTemplate:
|
|
|
|
return TypeSpecWithTemplate;
|
|
|
|
}
|
|
|
|
|
2012-01-21 05:50:17 +08:00
|
|
|
llvm_unreachable("Invalid NNS Kind!");
|
2011-02-24 10:36:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the namespace stored in this nested name
|
|
|
|
/// specifier.
|
|
|
|
NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
|
|
|
|
if (Prefix.getInt() == StoredNamespaceOrAlias)
|
|
|
|
return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the namespace alias stored in this nested name
|
|
|
|
/// specifier.
|
|
|
|
NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
|
|
|
|
if (Prefix.getInt() == StoredNamespaceOrAlias)
|
|
|
|
return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
/// \brief Whether this nested name specifier refers to a dependent
|
|
|
|
/// type or not.
|
|
|
|
bool NestedNameSpecifier::isDependent() const {
|
|
|
|
switch (getKind()) {
|
|
|
|
case Identifier:
|
|
|
|
// Identifier specifiers always represent dependent types
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case Namespace:
|
2011-02-24 10:36:08 +08:00
|
|
|
case NamespaceAlias:
|
2009-03-27 07:50:42 +08:00
|
|
|
case Global:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case TypeSpec:
|
|
|
|
case TypeSpecWithTemplate:
|
|
|
|
return getAsType()->isDependentType();
|
2009-03-19 11:51:16 +08:00
|
|
|
}
|
2009-03-27 07:50:42 +08:00
|
|
|
|
2012-01-21 05:50:17 +08:00
|
|
|
llvm_unreachable("Invalid NNS Kind!");
|
2009-03-27 07:50:42 +08:00
|
|
|
}
|
|
|
|
|
2011-07-01 09:22:09 +08:00
|
|
|
/// \brief Whether this nested name specifier refers to a dependent
|
|
|
|
/// type or not.
|
|
|
|
bool NestedNameSpecifier::isInstantiationDependent() const {
|
|
|
|
switch (getKind()) {
|
|
|
|
case Identifier:
|
|
|
|
// Identifier specifiers always represent dependent types
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case Namespace:
|
|
|
|
case NamespaceAlias:
|
|
|
|
case Global:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case TypeSpec:
|
|
|
|
case TypeSpecWithTemplate:
|
|
|
|
return getAsType()->isInstantiationDependentType();
|
|
|
|
}
|
2012-01-21 05:50:17 +08:00
|
|
|
|
|
|
|
llvm_unreachable("Invalid NNS Kind!");
|
2011-07-01 09:22:09 +08:00
|
|
|
}
|
|
|
|
|
Variadic templates: extend Type, NestedNameSpecifier, TemplateName,
and TemplateArgument with an operation that determines whether there
are any unexpanded parameter packs within that construct. Use this
information to diagnose the appearance of the names of parameter packs
that have not been expanded (C++ [temp.variadic]p5). Since this
property is checked often (every declaration, ever expression
statement, etc.), we extend Type and Expr with a bit storing the
result of this computation, rather than walking the AST each time to
determine whether any unexpanded parameter packs occur.
This commit is deficient in several ways, which will be remedied with
future commits:
- Expr has a bit to store the presence of an unexpanded parameter
pack, but it is never set.
- The error messages don't point out where the unexpanded parameter
packs were named in the type/expression, but they should.
- We don't check for unexpanded parameter packs in all of the places
where we should.
- Testing is sparse, pending the resolution of the above three
issues.
llvm-svn: 121724
2010-12-14 06:49:22 +08:00
|
|
|
bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
|
|
|
|
switch (getKind()) {
|
|
|
|
case Identifier:
|
|
|
|
return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
|
|
|
|
|
|
|
|
case Namespace:
|
2011-02-24 10:36:08 +08:00
|
|
|
case NamespaceAlias:
|
Variadic templates: extend Type, NestedNameSpecifier, TemplateName,
and TemplateArgument with an operation that determines whether there
are any unexpanded parameter packs within that construct. Use this
information to diagnose the appearance of the names of parameter packs
that have not been expanded (C++ [temp.variadic]p5). Since this
property is checked often (every declaration, ever expression
statement, etc.), we extend Type and Expr with a bit storing the
result of this computation, rather than walking the AST each time to
determine whether any unexpanded parameter packs occur.
This commit is deficient in several ways, which will be remedied with
future commits:
- Expr has a bit to store the presence of an unexpanded parameter
pack, but it is never set.
- The error messages don't point out where the unexpanded parameter
packs were named in the type/expression, but they should.
- We don't check for unexpanded parameter packs in all of the places
where we should.
- Testing is sparse, pending the resolution of the above three
issues.
llvm-svn: 121724
2010-12-14 06:49:22 +08:00
|
|
|
case Global:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case TypeSpec:
|
|
|
|
case TypeSpecWithTemplate:
|
|
|
|
return getAsType()->containsUnexpandedParameterPack();
|
|
|
|
}
|
|
|
|
|
2012-01-21 05:50:17 +08:00
|
|
|
llvm_unreachable("Invalid NNS Kind!");
|
Variadic templates: extend Type, NestedNameSpecifier, TemplateName,
and TemplateArgument with an operation that determines whether there
are any unexpanded parameter packs within that construct. Use this
information to diagnose the appearance of the names of parameter packs
that have not been expanded (C++ [temp.variadic]p5). Since this
property is checked often (every declaration, ever expression
statement, etc.), we extend Type and Expr with a bit storing the
result of this computation, rather than walking the AST each time to
determine whether any unexpanded parameter packs occur.
This commit is deficient in several ways, which will be remedied with
future commits:
- Expr has a bit to store the presence of an unexpanded parameter
pack, but it is never set.
- The error messages don't point out where the unexpanded parameter
packs were named in the type/expression, but they should.
- We don't check for unexpanded parameter packs in all of the places
where we should.
- Testing is sparse, pending the resolution of the above three
issues.
llvm-svn: 121724
2010-12-14 06:49:22 +08:00
|
|
|
}
|
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
/// \brief Print this nested name specifier to the given output
|
|
|
|
/// stream.
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2011-07-23 18:55:15 +08:00
|
|
|
NestedNameSpecifier::print(raw_ostream &OS,
|
2009-05-30 04:38:28 +08:00
|
|
|
const PrintingPolicy &Policy) const {
|
2009-04-01 08:28:59 +08:00
|
|
|
if (getPrefix())
|
2009-05-30 04:38:28 +08:00
|
|
|
getPrefix()->print(OS, Policy);
|
2009-03-27 07:50:42 +08:00
|
|
|
|
|
|
|
switch (getKind()) {
|
|
|
|
case Identifier:
|
|
|
|
OS << getAsIdentifier()->getName();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Namespace:
|
2011-11-03 08:16:13 +08:00
|
|
|
if (getAsNamespace()->isAnonymousNamespace())
|
|
|
|
return;
|
|
|
|
|
2011-02-24 10:36:08 +08:00
|
|
|
OS << getAsNamespace()->getName();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NamespaceAlias:
|
|
|
|
OS << getAsNamespaceAlias()->getName();
|
2009-03-27 07:50:42 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Global:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TypeSpecWithTemplate:
|
|
|
|
OS << "template ";
|
|
|
|
// Fall through to print the type.
|
|
|
|
|
|
|
|
case TypeSpec: {
|
2011-01-19 14:33:43 +08:00
|
|
|
const Type *T = getAsType();
|
2009-03-27 07:50:42 +08:00
|
|
|
|
2009-05-30 04:38:28 +08:00
|
|
|
PrintingPolicy InnerPolicy(Policy);
|
2009-09-05 14:31:47 +08:00
|
|
|
InnerPolicy.SuppressScope = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-26 08:04:55 +08:00
|
|
|
// Nested-name-specifiers are intended to contain minimally-qualified
|
2010-05-12 05:36:43 +08:00
|
|
|
// types. An actual ElaboratedType will not occur, since we'll store
|
2009-08-26 08:04:55 +08:00
|
|
|
// just the type that is referred to in the nested-name-specifier (e.g.,
|
|
|
|
// a TypedefType, TagType, etc.). However, when we are dealing with
|
2009-09-09 23:08:12 +08:00
|
|
|
// dependent template-id types (e.g., Outer<T>::template Inner<U>),
|
2009-08-26 08:04:55 +08:00
|
|
|
// the type requires its own nested-name-specifier for uniqueness, so we
|
|
|
|
// suppress that nested-name-specifier during printing.
|
2010-05-12 05:36:43 +08:00
|
|
|
assert(!isa<ElaboratedType>(T) &&
|
|
|
|
"Elaborated type in nested-name-specifier");
|
2009-08-26 08:04:55 +08:00
|
|
|
if (const TemplateSpecializationType *SpecType
|
|
|
|
= dyn_cast<TemplateSpecializationType>(T)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Print the template name without its corresponding
|
2009-08-26 08:04:55 +08:00
|
|
|
// nested-name-specifier.
|
|
|
|
SpecType->getTemplateName().print(OS, InnerPolicy, true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-26 08:04:55 +08:00
|
|
|
// Print the template argument list.
|
2013-02-22 23:46:01 +08:00
|
|
|
TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
OS, SpecType->getArgs(), SpecType->getNumArgs(), InnerPolicy);
|
2009-08-26 08:04:55 +08:00
|
|
|
} else {
|
|
|
|
// Print the type normally
|
2013-02-22 23:46:01 +08:00
|
|
|
QualType(T, 0).print(OS, InnerPolicy);
|
2009-08-26 08:04:55 +08:00
|
|
|
}
|
2009-03-27 07:50:42 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << "::";
|
|
|
|
}
|
|
|
|
|
2009-06-30 09:26:17 +08:00
|
|
|
void NestedNameSpecifier::dump(const LangOptions &LO) {
|
|
|
|
print(llvm::errs(), PrintingPolicy(LO));
|
2009-03-28 07:10:48 +08:00
|
|
|
}
|
2011-02-25 01:54:50 +08:00
|
|
|
|
|
|
|
unsigned
|
|
|
|
NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) {
|
|
|
|
assert(Qualifier && "Expected a non-NULL qualifier");
|
|
|
|
|
|
|
|
// Location of the trailing '::'.
|
|
|
|
unsigned Length = sizeof(unsigned);
|
|
|
|
|
|
|
|
switch (Qualifier->getKind()) {
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
// Nothing more to add.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
case NestedNameSpecifier::NamespaceAlias:
|
|
|
|
// The location of the identifier or namespace name.
|
|
|
|
Length += sizeof(unsigned);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate:
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
// The "void*" that points at the TypeLoc data.
|
|
|
|
// Note: the 'template' keyword is part of the TypeLoc.
|
|
|
|
Length += sizeof(void *);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Length;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) {
|
|
|
|
unsigned Length = 0;
|
|
|
|
for (; Qualifier; Qualifier = Qualifier->getPrefix())
|
|
|
|
Length += getLocalDataLength(Qualifier);
|
|
|
|
return Length;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// \brief Load a (possibly unaligned) source location from a given address
|
|
|
|
/// and offset.
|
|
|
|
SourceLocation LoadSourceLocation(void *Data, unsigned Offset) {
|
|
|
|
unsigned Raw;
|
|
|
|
memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned));
|
|
|
|
return SourceLocation::getFromRawEncoding(Raw);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Load a (possibly unaligned) pointer from a given address and
|
|
|
|
/// offset.
|
|
|
|
void *LoadPointer(void *Data, unsigned Offset) {
|
|
|
|
void *Result;
|
|
|
|
memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*));
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-25 08:36:19 +08:00
|
|
|
SourceRange NestedNameSpecifierLoc::getSourceRange() const {
|
2011-02-26 00:33:46 +08:00
|
|
|
if (!Qualifier)
|
|
|
|
return SourceRange();
|
|
|
|
|
2011-02-25 01:54:50 +08:00
|
|
|
NestedNameSpecifierLoc First = *this;
|
2011-02-26 00:33:46 +08:00
|
|
|
while (NestedNameSpecifierLoc Prefix = First.getPrefix())
|
2011-02-25 01:54:50 +08:00
|
|
|
First = Prefix;
|
|
|
|
|
|
|
|
return SourceRange(First.getLocalSourceRange().getBegin(),
|
|
|
|
getLocalSourceRange().getEnd());
|
|
|
|
}
|
|
|
|
|
2011-02-25 08:36:19 +08:00
|
|
|
SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
|
2011-02-26 00:33:46 +08:00
|
|
|
if (!Qualifier)
|
|
|
|
return SourceRange();
|
|
|
|
|
2011-02-25 01:54:50 +08:00
|
|
|
unsigned Offset = getDataLength(Qualifier->getPrefix());
|
|
|
|
switch (Qualifier->getKind()) {
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
return LoadSourceLocation(Data, Offset);
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
case NestedNameSpecifier::NamespaceAlias:
|
|
|
|
return SourceRange(LoadSourceLocation(Data, Offset),
|
|
|
|
LoadSourceLocation(Data, Offset + sizeof(unsigned)));
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate:
|
|
|
|
case NestedNameSpecifier::TypeSpec: {
|
|
|
|
// The "void*" that points at the TypeLoc data.
|
|
|
|
// Note: the 'template' keyword is part of the TypeLoc.
|
|
|
|
void *TypeData = LoadPointer(Data, Offset);
|
|
|
|
TypeLoc TL(Qualifier->getAsType(), TypeData);
|
|
|
|
return SourceRange(TL.getBeginLoc(),
|
|
|
|
LoadSourceLocation(Data, Offset + sizeof(void*)));
|
|
|
|
}
|
|
|
|
}
|
2012-01-21 05:50:17 +08:00
|
|
|
|
|
|
|
llvm_unreachable("Invalid NNS Kind!");
|
2011-02-25 01:54:50 +08:00
|
|
|
}
|
2011-02-25 08:36:19 +08:00
|
|
|
|
|
|
|
TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
|
|
|
|
assert((Qualifier->getKind() == NestedNameSpecifier::TypeSpec ||
|
|
|
|
Qualifier->getKind() == NestedNameSpecifier::TypeSpecWithTemplate) &&
|
|
|
|
"Nested-name-specifier location is not a type");
|
|
|
|
|
|
|
|
// The "void*" that points at the TypeLoc data.
|
|
|
|
unsigned Offset = getDataLength(Qualifier->getPrefix());
|
|
|
|
void *TypeData = LoadPointer(Data, Offset);
|
|
|
|
return TypeLoc(Qualifier->getAsType(), TypeData);
|
|
|
|
}
|
2011-03-01 07:58:31 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
|
|
|
|
unsigned &BufferCapacity) {
|
|
|
|
if (BufferSize + (End - Start) > BufferCapacity) {
|
|
|
|
// Reallocate the buffer.
|
|
|
|
unsigned NewCapacity
|
|
|
|
= std::max((unsigned)(BufferCapacity? BufferCapacity * 2
|
|
|
|
: sizeof(void*) * 2),
|
|
|
|
(unsigned)(BufferSize + (End - Start)));
|
|
|
|
char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
|
|
|
|
memcpy(NewBuffer, Buffer, BufferSize);
|
|
|
|
|
|
|
|
if (BufferCapacity)
|
|
|
|
free(Buffer);
|
|
|
|
Buffer = NewBuffer;
|
|
|
|
BufferCapacity = NewCapacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(Buffer + BufferSize, Start, End - Start);
|
|
|
|
BufferSize += End-Start;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Save a source location to the given buffer.
|
|
|
|
void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
|
|
|
|
unsigned &BufferSize, unsigned &BufferCapacity) {
|
|
|
|
unsigned Raw = Loc.getRawEncoding();
|
|
|
|
Append(reinterpret_cast<char *>(&Raw),
|
|
|
|
reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
|
|
|
|
Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Save a pointer to the given buffer.
|
|
|
|
void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
|
|
|
|
unsigned &BufferCapacity) {
|
|
|
|
Append(reinterpret_cast<char *>(&Ptr),
|
|
|
|
reinterpret_cast<char *>(&Ptr) + sizeof(void *),
|
|
|
|
Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifierLocBuilder::
|
|
|
|
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)
|
|
|
|
: Representation(Other.Representation), Buffer(0),
|
|
|
|
BufferSize(0), BufferCapacity(0)
|
|
|
|
{
|
|
|
|
if (!Other.Buffer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Other.BufferCapacity == 0) {
|
|
|
|
// Shallow copy is okay.
|
|
|
|
Buffer = Other.Buffer;
|
|
|
|
BufferSize = Other.BufferSize;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deep copy
|
|
|
|
BufferSize = Other.BufferSize;
|
|
|
|
BufferCapacity = Other.BufferSize;
|
|
|
|
Buffer = static_cast<char *>(malloc(BufferCapacity));
|
|
|
|
memcpy(Buffer, Other.Buffer, BufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifierLocBuilder &
|
|
|
|
NestedNameSpecifierLocBuilder::
|
|
|
|
operator=(const NestedNameSpecifierLocBuilder &Other) {
|
|
|
|
Representation = Other.Representation;
|
|
|
|
|
|
|
|
if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
|
|
|
|
// Re-use our storage.
|
|
|
|
BufferSize = Other.BufferSize;
|
|
|
|
memcpy(Buffer, Other.Buffer, BufferSize);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free our storage, if we have any.
|
|
|
|
if (BufferCapacity) {
|
|
|
|
free(Buffer);
|
|
|
|
BufferCapacity = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Other.Buffer) {
|
|
|
|
// Empty.
|
|
|
|
Buffer = 0;
|
|
|
|
BufferSize = 0;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Other.BufferCapacity == 0) {
|
|
|
|
// Shallow copy is okay.
|
|
|
|
Buffer = Other.Buffer;
|
|
|
|
BufferSize = Other.BufferSize;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deep copy.
|
|
|
|
BufferSize = Other.BufferSize;
|
|
|
|
BufferCapacity = BufferSize;
|
|
|
|
Buffer = static_cast<char *>(malloc(BufferSize));
|
|
|
|
memcpy(Buffer, Other.Buffer, BufferSize);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
|
|
|
|
SourceLocation TemplateKWLoc,
|
|
|
|
TypeLoc TL,
|
|
|
|
SourceLocation ColonColonLoc) {
|
|
|
|
Representation = NestedNameSpecifier::Create(Context, Representation,
|
|
|
|
TemplateKWLoc.isValid(),
|
|
|
|
TL.getTypePtr());
|
|
|
|
|
|
|
|
// Push source-location info into the buffer.
|
|
|
|
SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
|
|
|
|
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
|
|
|
|
IdentifierInfo *Identifier,
|
|
|
|
SourceLocation IdentifierLoc,
|
|
|
|
SourceLocation ColonColonLoc) {
|
|
|
|
Representation = NestedNameSpecifier::Create(Context, Representation,
|
|
|
|
Identifier);
|
|
|
|
|
|
|
|
// Push source-location info into the buffer.
|
|
|
|
SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
|
|
|
|
NamespaceDecl *Namespace,
|
|
|
|
SourceLocation NamespaceLoc,
|
|
|
|
SourceLocation ColonColonLoc) {
|
|
|
|
Representation = NestedNameSpecifier::Create(Context, Representation,
|
|
|
|
Namespace);
|
|
|
|
|
|
|
|
// Push source-location info into the buffer.
|
|
|
|
SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
|
|
|
|
NamespaceAliasDecl *Alias,
|
|
|
|
SourceLocation AliasLoc,
|
|
|
|
SourceLocation ColonColonLoc) {
|
|
|
|
Representation = NestedNameSpecifier::Create(Context, Representation, Alias);
|
|
|
|
|
|
|
|
// Push source-location info into the buffer.
|
|
|
|
SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context,
|
|
|
|
SourceLocation ColonColonLoc) {
|
|
|
|
assert(!Representation && "Already have a nested-name-specifier!?");
|
|
|
|
Representation = NestedNameSpecifier::GlobalSpecifier(Context);
|
|
|
|
|
|
|
|
// Push source-location info into the buffer.
|
|
|
|
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
|
|
|
|
NestedNameSpecifier *Qualifier,
|
|
|
|
SourceRange R) {
|
|
|
|
Representation = Qualifier;
|
|
|
|
|
|
|
|
// Construct bogus (but well-formed) source information for the
|
|
|
|
// nested-name-specifier.
|
|
|
|
BufferSize = 0;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<NestedNameSpecifier *, 4> Stack;
|
2011-03-01 07:58:31 +08:00
|
|
|
for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
|
|
|
|
Stack.push_back(NNS);
|
|
|
|
while (!Stack.empty()) {
|
2013-08-24 00:11:15 +08:00
|
|
|
NestedNameSpecifier *NNS = Stack.pop_back_val();
|
2011-03-01 07:58:31 +08:00
|
|
|
switch (NNS->getKind()) {
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
case NestedNameSpecifier::NamespaceAlias:
|
|
|
|
SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate: {
|
|
|
|
TypeSourceInfo *TSInfo
|
|
|
|
= Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
|
|
|
|
R.getBegin());
|
|
|
|
SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
|
|
|
|
BufferCapacity);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the location of the '::'.
|
|
|
|
SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(),
|
|
|
|
Buffer, BufferSize, BufferCapacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
|
|
|
|
if (BufferCapacity)
|
|
|
|
free(Buffer);
|
|
|
|
|
|
|
|
if (!Other) {
|
|
|
|
Representation = 0;
|
|
|
|
BufferSize = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rather than copying the data (which is wasteful), "adopt" the
|
|
|
|
// pointer (which points into the ASTContext) but set the capacity to zero to
|
|
|
|
// indicate that we don't own it.
|
|
|
|
Representation = Other.getNestedNameSpecifier();
|
|
|
|
Buffer = static_cast<char *>(Other.getOpaqueData());
|
|
|
|
BufferSize = Other.getDataLength();
|
|
|
|
BufferCapacity = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifierLoc
|
|
|
|
NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const {
|
|
|
|
if (!Representation)
|
|
|
|
return NestedNameSpecifierLoc();
|
|
|
|
|
|
|
|
// If we adopted our data pointer from elsewhere in the AST context, there's
|
|
|
|
// no need to copy the memory.
|
|
|
|
if (BufferCapacity == 0)
|
|
|
|
return NestedNameSpecifierLoc(Representation, Buffer);
|
|
|
|
|
|
|
|
// FIXME: After copying the source-location information, should we free
|
|
|
|
// our (temporary) buffer and adopt the ASTContext-allocated memory?
|
|
|
|
// Doing so would optimize repeated calls to getWithLocInContext().
|
|
|
|
void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
|
|
|
|
memcpy(Mem, Buffer, BufferSize);
|
|
|
|
return NestedNameSpecifierLoc(Representation, Mem);
|
|
|
|
}
|