From d186829093e8c9b2d96cb5b10c81a6e78519e33b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 29 Apr 2018 05:33:38 +0000 Subject: [PATCH] Fix printing of reference-to-reference types. Previously we would sometimes print these as 'T &&&' or even 'T &&&&'. llvm-svn: 331137 --- clang/lib/AST/TypePrinter.cpp | 28 ++++++++++++++++++++-------- clang/test/SemaCXX/references.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 743e35e..c99148e 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -385,14 +385,23 @@ void TypePrinter::printBlockPointerAfter(const BlockPointerType *T, printAfter(T->getPointeeType(), OS); } +// When printing a reference, the referenced type might also be a reference. +// If so, we want to skip that before printing the inner type. +static QualType skipTopLevelReferences(QualType T) { + if (auto *Ref = T->getAs()) + return skipTopLevelReferences(Ref->getPointeeTypeAsWritten()); + return T; +} + void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); - printBefore(T->getPointeeTypeAsWritten(), OS); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); + printBefore(Inner, OS); // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa(T->getPointeeTypeAsWritten())) + if (isa(Inner)) OS << '('; OS << '&'; } @@ -401,21 +410,23 @@ void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa(T->getPointeeTypeAsWritten())) + if (isa(Inner)) OS << ')'; - printAfter(T->getPointeeTypeAsWritten(), OS); + printAfter(Inner, OS); } void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); - printBefore(T->getPointeeTypeAsWritten(), OS); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); + printBefore(Inner, OS); // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa(T->getPointeeTypeAsWritten())) + if (isa(Inner)) OS << '('; OS << "&&"; } @@ -424,11 +435,12 @@ void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa(T->getPointeeTypeAsWritten())) + if (isa(Inner)) OS << ')'; - printAfter(T->getPointeeTypeAsWritten(), OS); + printAfter(Inner, OS); } void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, diff --git a/clang/test/SemaCXX/references.cpp b/clang/test/SemaCXX/references.cpp index dc59d50..b34b740 100644 --- a/clang/test/SemaCXX/references.cpp +++ b/clang/test/SemaCXX/references.cpp @@ -154,3 +154,31 @@ namespace ExplicitRefInit { struct A { explicit A(int); }; const A &a(0); // expected-error {{reference to type 'const ExplicitRefInit::A' could not bind to an rvalue of type 'int'}} } + +namespace RefCollapseTypePrinting { + template void add_lref() { + using X = int(T); // expected-note 4{{previous}} + using X = const volatile T&; + // expected-error@-1 {{'int &' vs 'int (int &)'}} + // expected-error@-2 {{'int &' vs 'int (int &&)'}} + // expected-error@-3 {{'const int &' vs 'int (const int &)'}} + // expected-error@-4 {{'const int &' vs 'int (const int &&)'}} + } + template void add_lref(); // expected-note {{instantiation of}} + template void add_lref(); // expected-note {{instantiation of}} + template void add_lref(); // expected-note {{instantiation of}} + template void add_lref(); // expected-note {{instantiation of}} + + template void add_rref() { + using X = int(T); // expected-note 4{{previous}} + using X = const volatile T&&; + // expected-error@-1 {{'int &' vs 'int (int &)'}} + // expected-error@-2 {{'int &&' vs 'int (int &&)'}} + // expected-error@-3 {{'const int &' vs 'int (const int &)'}} + // expected-error@-4 {{'const int &&' vs 'int (const int &&)'}} + } + template void add_rref(); // expected-note {{instantiation of}} + template void add_rref(); // expected-note {{instantiation of}} + template void add_rref(); // expected-note {{instantiation of}} + template void add_rref(); // expected-note {{instantiation of}} +} -- 2.7.4