Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,9 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
// Collect named contexts.
DeclarationName NameInScope = getDeclName();
for (; Ctx; Ctx = Ctx->getParent()) {
if (P.Callbacks && P.Callbacks->isScopeVisible(Ctx))
continue;

// Suppress anonymous namespace if requested.
if (P.SuppressUnwrittenScope && isa<NamespaceDecl>(Ctx) &&
cast<NamespaceDecl>(Ctx)->isAnonymousNamespace())
Expand Down
67 changes: 6 additions & 61 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,6 @@ class TypePrinter {

void printBefore(QualType T, raw_ostream &OS);
void printAfter(QualType T, raw_ostream &OS);
void AppendScope(DeclContext *DC, raw_ostream &OS,
DeclarationName NameInScope);
void printTagType(const TagType *T, raw_ostream &OS);
void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
Expand Down Expand Up @@ -1226,7 +1224,7 @@ void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) {
// In C, this will always be empty except when the type
// being printed is anonymous within other Record.
if (!Policy.SuppressScope)
AppendScope(D->getDeclContext(), OS, D->getDeclName());
D->printNestedNameSpecifier(OS, Policy);

IdentifierInfo *II = D->getIdentifier();
OS << II->getName();
Expand All @@ -1240,7 +1238,7 @@ void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T,
OS << ' ';
auto *D = T->getDecl();
if (Policy.FullyQualifiedName || T->isCanonicalUnqualified()) {
AppendScope(D->getDeclContext(), OS, D->getDeclName());
D->printNestedNameSpecifier(OS, Policy);
} else {
T->getQualifier().print(OS, Policy);
}
Expand All @@ -1257,7 +1255,7 @@ void TypePrinter::printUsingBefore(const UsingType *T, raw_ostream &OS) {
OS << ' ';
auto *D = T->getDecl();
if (Policy.FullyQualifiedName) {
AppendScope(D->getDeclContext(), OS, D->getDeclName());
D->printNestedNameSpecifier(OS, Policy);
} else {
T->getQualifier().print(OS, Policy);
}
Expand All @@ -1273,7 +1271,7 @@ void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) {
OS << ' ';
auto *D = T->getDecl();
if (Policy.FullyQualifiedName) {
AppendScope(D->getDeclContext(), OS, D->getDeclName());
D->printNestedNameSpecifier(OS, Policy);
} else {
T->getQualifier().print(OS, Policy);
}
Expand Down Expand Up @@ -1511,59 +1509,6 @@ void TypePrinter::printPredefinedSugarBefore(const PredefinedSugarType *T,
void TypePrinter::printPredefinedSugarAfter(const PredefinedSugarType *T,
raw_ostream &OS) {}

/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS,
DeclarationName NameInScope) {
if (DC->isTranslationUnit())
return;

// FIXME: Consider replacing this with NamedDecl::printNestedNameSpecifier,
// which can also print names for function and method scopes.
if (DC->isFunctionOrMethod())
return;

if (Policy.Callbacks && Policy.Callbacks->isScopeVisible(DC))
return;

if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
if (Policy.SuppressUnwrittenScope && NS->isAnonymousNamespace())
return AppendScope(DC->getParent(), OS, NameInScope);

// Only suppress an inline namespace if the name has the same lookup
// results in the enclosing namespace.
if (Policy.SuppressInlineNamespace !=
PrintingPolicy::SuppressInlineNamespaceMode::None &&
NS->isInline() && NameInScope &&
NS->isRedundantInlineQualifierFor(NameInScope))
return AppendScope(DC->getParent(), OS, NameInScope);

AppendScope(DC->getParent(), OS, NS->getDeclName());
if (NS->getIdentifier())
OS << NS->getName() << "::";
else
OS << "(anonymous namespace)::";
} else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
AppendScope(DC->getParent(), OS, Spec->getDeclName());
IncludeStrongLifetimeRAII Strong(Policy);
OS << Spec->getIdentifier()->getName();
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
printTemplateArgumentList(
OS, TemplateArgs.asArray(), Policy,
Spec->getSpecializedTemplate()->getTemplateParameters());
OS << "::";
} else if (const auto *Tag = dyn_cast<TagDecl>(DC)) {
AppendScope(DC->getParent(), OS, Tag->getDeclName());
if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
OS << Typedef->getIdentifier()->getName() << "::";
else if (Tag->getIdentifier())
OS << Tag->getIdentifier()->getName() << "::";
else
return;
} else {
AppendScope(DC->getParent(), OS, NameInScope);
}
}

void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
TagDecl *D = T->getDecl();

Expand Down Expand Up @@ -1593,7 +1538,7 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
// Compute the full nested-name-specifier for this type.
// In C, this will always be empty except when the type
// being printed is anonymous within other Record.
AppendScope(D->getDeclContext(), OS, D->getDeclName());
D->printNestedNameSpecifier(OS, Policy);
}

if (const IdentifierInfo *II = D->getIdentifier())
Expand Down Expand Up @@ -1809,7 +1754,7 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
// FIXME: Null TD never exercised in test suite.
if (FullyQualify && TD) {
if (!Policy.SuppressScope)
AppendScope(TD->getDeclContext(), OS, TD->getDeclName());
TD->printNestedNameSpecifier(OS, Policy);

OS << TD->getName();
} else {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/ASTMerge/struct/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
// CHECK: struct2.c:72:7: note: field 'i' has type 'int' here
// CHECK: struct2.c:76:5: warning: external variable 'x13' declared with incompatible types in different translation units ('S13' vs. 'S13')
// CHECK: struct1.c:79:5: note: declared here with type 'S13'
// CHECK: struct1.c:130:7: warning: type 'struct DeepUnnamedError::(unnamed at [[PATH_TO_INPUTS:.+]]struct1.c:130:7)' has incompatible definitions in different translation units
// CHECK: struct1.c:130:7: warning: type 'struct DeepUnnamedError::(anonymous union)::(anonymous union)::(unnamed at [[PATH_TO_INPUTS:.+]]struct1.c:130:7)' has incompatible definitions in different translation units
// CHECK: struct1.c:131:14: note: field 'i' has type 'long' here
// CHECK: struct2.c:128:15: note: field 'i' has type 'float' here
// CHECK: struct1.c:129:5: warning: type 'union DeepUnnamedError::(unnamed at [[PATH_TO_INPUTS]]struct1.c:129:5)' has incompatible definitions in different translation units
// CHECK: struct1.c:129:5: warning: type 'union DeepUnnamedError::(anonymous union)::(unnamed at [[PATH_TO_INPUTS]]struct1.c:129:5)' has incompatible definitions in different translation units
// CHECK: struct1.c:132:9: note: field 'S' has type 'struct (unnamed struct at [[PATH_TO_INPUTS]]struct1.c:130:7)' here
// CHECK: struct2.c:129:9: note: field 'S' has type 'struct (unnamed struct at [[PATH_TO_INPUTS]]struct2.c:127:7)' here
// CHECK: struct2.c:138:3: warning: external variable 'x16' declared with incompatible types in different translation units ('struct DeepUnnamedError' vs. 'struct DeepUnnamedError')
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/drs/cwg6xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ namespace cwg686 { // cwg686: 3.0
#endif
struct N {
operator struct O{}(){};
// expected-error@-1 {{'N::O' cannot be defined in a type specifier}}
// expected-error@-1 {{'cwg686::f()::N::O' cannot be defined in a type specifier}}
};
try {}
catch (struct P *) {}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Index/print-type.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ _Atomic(unsigned long) aul;
// CHECK: TypeRef=struct Struct:16:8 [type=struct Struct] [typekind=Record] [isPOD=1]
// CHECK: StructDecl=struct (unnamed at {{.*}}):18:1 (Definition) [type=struct (unnamed at {{.*}}print-type.c:18:1)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=0]
// CHECK: StructDecl=struct (unnamed at {{.*}}):23:1 (Definition) [type=struct (unnamed at {{.*}}print-type.c:23:1)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1] [isAnonRecDecl=0]
// CHECK: StructDecl=struct (anonymous at {{.*}}):24:3 (Definition) [type=struct (anonymous at {{.*}}print-type.c:24:3)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=1]
// CHECK: StructDecl=struct (anonymous at {{.*}}):24:3 (Definition) [type=struct (anonymous struct)::(anonymous at {{.*}}print-type.c:24:3)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=1]
// CHECK: FieldDecl=x:25:17 (Definition) [type=_Atomic(int)] [typekind=Atomic] [valuetype=int] [valuetypekind=Int] [isPOD=0] [isAnonRecDecl=0]
// CHECK: FieldDecl=y:26:9 (Definition) [type=int] [typekind=Int] [isPOD=1] [isAnonRecDecl=0]
// CHECK: StructDecl=struct (unnamed at {{.*}}):30:10 (Definition) [type=struct (unnamed at {{.*}}print-type.c:30:10)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=0]
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct AT3 : AT2, AT1 {
// CHECK-NEXT: 0 | struct AT2 (base)
// CHECK-NEXT: 0 | struct AT0 t
// CHECK-NEXT: 0 | union AT0::(unnamed at {{.*}} x
// CHECK-NEXT: 0 | struct AT0::(unnamed at {{.*}} y
// CHECK-NEXT: 0 | struct AT0::(anonymous union)::(unnamed at {{.*}} y
// CHECK-NEXT: 0 | int a
// CHECK-NEXT: 4 | struct AT t (empty)
// CHECK: 0 | int b
Expand All @@ -66,7 +66,7 @@ struct AT3 : AT2, AT1 {
// CHECK-X64-NEXT: 0 | struct AT2 (base)
// CHECK-X64-NEXT: 0 | struct AT0 t
// CHECK-X64-NEXT: 0 | union AT0::(unnamed at {{.*}} x
// CHECK-X64-NEXT: 0 | struct AT0::(unnamed at {{.*}} y
// CHECK-X64-NEXT: 0 | struct AT0::(anonymous union)::(unnamed at {{.*}} y
// CHECK-X64-NEXT: 0 | int a
// CHECK-X64-NEXT: 4 | struct AT t (empty)
// CHECK-X64: 0 | int b
Expand Down
3 changes: 2 additions & 1 deletion clang/test/Modules/compare-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ struct CompareAnonymousNestedStruct compareAnonymousNestedStruct;
// [email protected]:* {{declaration of 'anonymousNestedStructField' does not match}}
#elif defined(CASE3)
struct CompareDeeplyNestedAnonymousUnionsAndStructs compareDeeplyNested;
// [email protected]:* {{'CompareDeeplyNestedAnonymousUnionsAndStructs::(anonymous union)::(anonymous union)::(anonymous struct)::z' from module 'Second' is not present in definition of 'struct CompareDeeplyNestedAnonymousUnionsAndStructs::(anonymous at {{.*}})' in module 'First.Hidden'}}
// [email protected]:* {{'CompareDeeplyNestedAnonymousUnionsAndStructs::(anonymous union)::(anonymous union)::(anonymous struct)::z' from module 'Second' is not present in definition of 'struct CompareDeeplyNestedAnonymousUnionsAndStructs::(anonymous union)::(anonymous union)::(anonymous at {{.*}})' in module 'First.Hidden'}}

// [email protected]:* {{declaration of 'z' does not match}}
#endif
8 changes: 4 additions & 4 deletions clang/test/SemaObjCXX/arc-0x.mm
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ void test() {

struct S1 {
union {
union { // expected-note-re {{copy constructor of 'S1' is implicitly deleted because field 'test_union::S1::(anonymous union at {{.*}})' has a deleted copy constructor}} expected-note-re {{copy assignment operator of 'S1' is implicitly deleted because field 'test_union::S1::(anonymous union at {{.*}})' has a deleted copy assignment operator}} expected-note-re 4 {{'S1' is implicitly deleted because field 'test_union::S1::(anonymous union at {{.*}})' has a deleted}}
union { // expected-note-re {{copy constructor of 'S1' is implicitly deleted because field 'test_union::S1::(anonymous union)::(anonymous union at {{.*}})' has a deleted copy constructor}} expected-note-re {{copy assignment operator of 'S1' is implicitly deleted because field 'test_union::S1::(anonymous union)::(anonymous union at {{.*}})' has a deleted copy assignment operator}} expected-note-re 4 {{'S1' is implicitly deleted because field 'test_union::S1::(anonymous union)::(anonymous union at {{.*}})' has a deleted}}
id f0; // expected-note-re 2 {{{{.*}} of '(anonymous union at {{.*}}' is implicitly deleted because variant field 'f0' is an ObjC pointer}}
char f1;
};
Expand All @@ -173,7 +173,7 @@ void test() {
struct S2 {
union {
// FIXME: the note should say 'f0' is causing the special functions to be deleted.
struct { // expected-note-re 6 {{'S2' is implicitly deleted because variant field 'test_union::S2::(anonymous struct at {{.*}})' has a non-trivial}}
struct { // expected-note-re 6 {{'S2' is implicitly deleted because variant field 'test_union::S2::(anonymous union)::(anonymous struct at {{.*}})' has a non-trivial}}
id f0;
int f1;
};
Expand All @@ -195,8 +195,8 @@ void test() {
};

static union { // expected-error {{call to implicitly-deleted default constructor of}}
union { // expected-note-re {{default constructor of '(unnamed union at {{.*}}' is implicitly deleted because field 'test_union::(anonymous union at {{.*}})' has a deleted default constructor}}
union { // expected-note-re {{default constructor of '(anonymous union at {{.*}}' is implicitly deleted because field 'test_union::(anonymous union at {{.*}})' has a deleted default constructor}}
union { // expected-note-re {{default constructor of '(unnamed union at {{.*}}' is implicitly deleted because field 'test_union::(anonymous union)::(anonymous union at {{.*}})' has a deleted default constructor}}
union { // expected-note-re {{default constructor of '(anonymous union at {{.*}}' is implicitly deleted because field 'test_union::(anonymous union)::(anonymous union)::(anonymous union at {{.*}})' has a deleted default constructor}}
__weak id g1; // expected-note-re {{default constructor of '(anonymous union at {{.*}}' is implicitly deleted because variant field 'g1' is an ObjC pointer}}
int g2;
};
Expand Down
46 changes: 46 additions & 0 deletions clang/unittests/AST/TypePrinterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,49 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
Ctx, Arg, Param, ArgList.asArray(), Params->getDepth()));
}
}

TEST(TypePrinter, NestedNameSpecifiers) {
constexpr char Code[] = R"cpp(
void level1() {
struct Inner {
Inner(int) {
struct {
union {} u;
} imem;
}
};
}
)cpp";

// Types scoped immediately inside a function don't print the function name in
// their scope.
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),
"struct (unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
Policy.AnonymousTagLocations = false;
}));

ASSERT_TRUE(PrintedTypeMatches(
Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),
"struct (unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = false;
Policy.AnonymousTagLocations = false;
}));

// Further levels of nesting print the entire scope.
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),
"union level1()::Inner::Inner(int)::(anonymous struct)::(unnamed)",
[](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
Policy.AnonymousTagLocations = false;
}));

ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),
"union (unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = false;
Policy.AnonymousTagLocations = false;
}));
}