Skip to content

Commit

Permalink
Support dependent splices in namespace alias definitions.
Browse files Browse the repository at this point in the history
Also give more helpful errors for illegal use of dependent splices in
using directives.

Closes issue #7.
  • Loading branch information
katzdm committed Mar 28, 2024
1 parent 9aada72 commit 28c0250
Show file tree
Hide file tree
Showing 16 changed files with 216 additions and 30 deletions.
8 changes: 6 additions & 2 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,10 +562,12 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
llvm::PointerIntPair<NamespaceDecl *, 2, unsigned>
AnonOrFirstNamespaceAndFlags;

NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
protected:
NamespaceDecl(Kind K, ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, NamespaceDecl *PrevDecl, bool Nested);

private:
using redeclarable_base = Redeclarable<NamespaceDecl>;

NamespaceDecl *getNextRedeclarationImpl() override;
Expand Down Expand Up @@ -689,7 +691,9 @@ class NamespaceDecl : public NamedDecl, public DeclContext,

// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Namespace; }
static bool classofKind(Kind K) {
return K >= firstNamespace && K <= lastNamespace;
}
static DeclContext *castToDeclContext(const NamespaceDecl *D) {
return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D));
}
Expand Down
36 changes: 36 additions & 0 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class CXXBasePaths;
class CXXConstructorDecl;
class CXXDestructorDecl;
class CXXFinalOverriderMap;
class CXXIndeterminateSpliceExpr;
class CXXIndirectPrimaryBaseSet;
class CXXMethodDecl;
class CXXRecordDecl;
Expand Down Expand Up @@ -3106,6 +3107,30 @@ class UsingDirectiveDecl : public NamedDecl {
static bool classofKind(Kind K) { return K == UsingDirective; }
};

class DependentNamespaceDecl : public NamespaceDecl {
friend class ASTDeclReader;

CXXIndeterminateSpliceExpr *SpliceExpr;

DependentNamespaceDecl(ASTContext &C, DeclContext *DC,
CXXIndeterminateSpliceExpr *SpliceExpr);

void anchor() override;

public:
static DependentNamespaceDecl *Create(ASTContext &C, DeclContext *DC,
CXXIndeterminateSpliceExpr *SpliceExpr);

static DependentNamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID);

CXXIndeterminateSpliceExpr *getSpliceExpr() const { return SpliceExpr; }

SourceRange getSourceRange() const override LLVM_READONLY;

static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == DependentNamespace; }
};

/// Represents a C++ namespace alias.
///
/// For example:
Expand Down Expand Up @@ -3197,6 +3222,17 @@ class NamespaceAliasDecl : public NamedDecl,
return const_cast<NamespaceAliasDecl *>(this)->getNamespace();
}

bool isDependent() const {
if (NestedNameSpecifier *Qualifier = getQualifier();
Qualifier && Qualifier->isDependent())
return true;

if (auto *AD = dyn_cast<NamespaceAliasDecl>(Namespace))
return AD->isDependent();

return isa<DependentNamespaceDecl>(Namespace);
}

/// Returns the location of the alias name, i.e. 'foo' in
/// "namespace foo = ns::bar;".
SourceLocation getAliasLoc() const { return getLocation(); }
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -5491,6 +5491,10 @@ class CXXIndeterminateSpliceExpr : public Expr {
return RSpliceLoc;
}

SourceRange getSourceRange() const {
return SourceRange(getBeginLoc(), getEndLoc());
}

child_range children() {
return child_range(reinterpret_cast<Stmt **>(&Operand),
reinterpret_cast<Stmt **>(&Operand) + 1);
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1646,6 +1646,10 @@ DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
ShouldVisitChildren = false;
})

DEF_TRAVERSE_DECL(DependentNamespaceDecl, {
TRY_TO(TraverseStmt(D->getSpliceExpr()));
})

DEF_TRAVERSE_DECL(LabelDecl, {// There is no code in a LabelDecl.
})

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DeclNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def PragmaDetectMismatch : DeclNode<Decl>;
def ExternCContext : DeclNode<Decl>, DeclContext;
def Named : DeclNode<Decl, "named declarations", 1>;
def Namespace : DeclNode<Named, "namespaces">, DeclContext;
def DependentNamespace : DeclNode<Namespace>;
def UsingDirective : DeclNode<Named>;
def NamespaceAlias : DeclNode<Named>;
def Label : DeclNode<Named, "labels">;
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3106,6 +3106,8 @@ def err_member_access_splice_not_class_member : Error<
"member of a class">;
def err_unsupported_splice_kind : Error<
"splicing %0 is %select{not|not yet}1 %select{supported|implemented}1">;
def err_using_dependent_namespace : Error<
"dependent namespaces cannot appear in a using directive">;

// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {

case Namespace:
case NamespaceAlias:
case DependentNamespace:
return IDNS_Namespace;

case FunctionTemplate:
Expand Down
40 changes: 32 additions & 8 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2959,11 +2959,11 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
return cast_or_null<NamespaceDecl>(NominatedNamespace);
}

NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, NamespaceDecl *PrevDecl,
bool Nested)
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
NamespaceDecl::NamespaceDecl(Kind K, ASTContext &C, DeclContext *DC,
bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
NamespaceDecl *PrevDecl, bool Nested)
: NamedDecl(K, DC, IdLoc, Id), DeclContext(Namespace),
redeclarable_base(C), LocStart(StartLoc) {
unsigned Flags = 0;
if (Inline)
Expand All @@ -2982,12 +2982,14 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
NamespaceDecl *PrevDecl, bool Nested) {
return new (C, DC)
NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested);
NamespaceDecl(Namespace, C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl,
Nested);
}

NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(),
SourceLocation(), nullptr, nullptr, false);
return new (C, ID) NamespaceDecl(Namespace, C, nullptr, false,
SourceLocation(), SourceLocation(), nullptr,
nullptr, false);
}

NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
Expand Down Expand Up @@ -3054,6 +3056,28 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
SourceLocation(), nullptr);
}

void DependentNamespaceDecl::anchor() {}

DependentNamespaceDecl::DependentNamespaceDecl(
ASTContext &C, DeclContext *DC, CXXIndeterminateSpliceExpr *SpliceExpr)
: NamespaceDecl(DependentNamespace, C, DC, false, SpliceExpr->getBeginLoc(),
SpliceExpr->getBeginLoc(), nullptr, nullptr, false),
SpliceExpr(SpliceExpr) {}

DependentNamespaceDecl *DependentNamespaceDecl::Create(
ASTContext &C, DeclContext *DC, CXXIndeterminateSpliceExpr *SpliceExpr) {
return new (C, DC) DependentNamespaceDecl(C, DC, SpliceExpr);
}

DependentNamespaceDecl *
DependentNamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) DependentNamespaceDecl(C, nullptr, nullptr);
}

SourceRange DependentNamespaceDecl::getSourceRange() const {
return SourceRange(SpliceExpr->getBeginLoc(), SpliceExpr->getEndLoc());
}

void LifetimeExtendedTemporaryDecl::anchor() {}

/// Retrieve the storage duration for the materialized temporary.
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/AST/NestedNameSpecifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,14 @@ NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const {
}

case Namespace:
case NamespaceAlias:
case Global:
return NestedNameSpecifierDependence::None;

case NamespaceAlias:
return getAsNamespaceAlias()->isDependent() ?
NestedNameSpecifierDependence::Dependent :
NestedNameSpecifierDependence::None;

case Super: {
CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier);
for (const auto &Base : RD->bases())
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::TranslationUnit:
case Decl::ExternCContext:
case Decl::Namespace:
case Decl::DependentNamespace:
case Decl::UnresolvedUsingTypename:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Sema/SemaCXXScopeSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,12 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
case NestedNameSpecifier::Namespace:
return NNS->getAsNamespace();

case NestedNameSpecifier::NamespaceAlias:
return NNS->getAsNamespaceAlias()->getNamespace();
case NestedNameSpecifier::NamespaceAlias: {
NamespaceAliasDecl *Alias = NNS->getAsNamespaceAlias();
if (Alias->isDependent())
return nullptr;
return Alias->getNamespace();
}

case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
Expand Down Expand Up @@ -505,6 +509,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
Found.setContextRange(SS.getRange());
} else if (ScopeLookupResult && isa<DependentNamespaceDecl>(ScopeLookupResult)) {
isDependent = true;
}

bool ObjectTypeSearchedInScope = false;
Expand Down
57 changes: 45 additions & 12 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12258,6 +12258,12 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
if (SS.isSet())
Qualifier = SS.getScopeRep();

if (Qualifier && Qualifier->isDependent()) {
Diag(SS.getBeginLoc(), diag::err_using_dependent_namespace)
<< SourceRange(SS.getBeginLoc(), IdentLoc);
return nullptr;
}

// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS);
Expand Down Expand Up @@ -12305,6 +12311,16 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
assert(IdentLoc.isValid() && "Invalid NamespceName location.");

// Check for dependent namespaces.
if (auto *DNSD = dyn_cast<DependentNamespaceDecl>(NS)) {
Diag(IdentLoc, diag::err_using_dependent_namespace)
<< DNSD->getSpliceExpr()->getSourceRange();
return nullptr;
} else if (auto *A = dyn_cast<NamespaceAliasDecl>(NS); A && A->isDependent()) {
Diag(IdentLoc, diag::err_using_dependent_namespace) << IdentLoc;
return nullptr;
}

// C++ [namespace.udir]p1:
// A using-directive specifies that the names in the nominated
// namespace can be used in the scope in which the
Expand Down Expand Up @@ -13746,23 +13762,36 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
IdentifierInfo *Alias, CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
NamedDecl *ND;

// Lookup the namespace name.
LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS);
// Scope may be dependent if it has a splice as a leading component of its
// qualifiers, and that splice is dependent on a template parameter.
if (NestedNameSpecifier *NNS = SS.getScopeRep(); NNS && NNS->isDependent()) {
ND = NamespaceDecl::Create(Context, CurContext, false, IdentLoc, IdentLoc,
Ident, nullptr, true);
} else {
// Lookup the namespace name.
LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);

if (R.isAmbiguous())
return nullptr;
if (S) {
LookupParsedName(R, S, &SS);
} else {
DeclContext *LookupCtx = computeDeclContext(SS, false);
LookupQualifiedName(R, LookupCtx);
}

if (R.empty()) {
if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
if (R.isAmbiguous())
return nullptr;

if (R.empty()) {
if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
return nullptr;
}
}
assert(!R.isAmbiguous() && !R.empty());
ND = R.getRepresentativeDecl();
}
assert(!R.isAmbiguous() && !R.empty());
NamedDecl *ND = R.getRepresentativeDecl();

return ActOnNamespaceAliasDef(S, NamespaceLoc, AliasLoc, Alias, SS, IdentLoc,
ND);
}
Expand Down Expand Up @@ -13823,7 +13852,11 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
if (Prev)
AliasDecl->setPreviousDecl(Prev);

PushOnScopeChains(AliasDecl, S);
if (S)
PushOnScopeChains(AliasDecl, S);
else
CurContext->addDecl(AliasDecl);

return AliasDecl;
}

Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Sema/SemaReflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,9 +611,10 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation LSplice,
DeclResult Sema::BuildReflectionSpliceNamespace(SourceLocation LSplice,
Expr *Operand,
SourceLocation RSplice) {
if (Operand->isTypeDependent() || Operand->isValueDependent())
llvm_unreachable("splicing of standalone dependent namespaces not yet "
"implemented");
if (Operand->isTypeDependent() || Operand->isValueDependent()) {
auto *Splice = cast<CXXIndeterminateSpliceExpr>(Operand);
return DependentNamespaceDecl::Create(Context, CurContext, Splice);
}

SmallVector<PartialDiagnosticAt, 4> Diags;
Expr::EvalResult ER;
Expand Down
Loading

0 comments on commit 28c0250

Please sign in to comment.