Add some tests for reference-collapsing and referencing binding

involving rvalue references, to start scoping out what is and what
isn't implemented. In the process, tweak some standards citations,
type desugaring, and teach the tentative parser about && in
ptr-operator.

llvm-svn: 123913
This commit is contained in:
Douglas Gregor 2011-01-20 16:08:06 +00:00
parent 6e5a54b36c
commit 7a2a116bab
6 changed files with 78 additions and 11 deletions

View File

@ -103,6 +103,9 @@ break; \
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
ShouldAKA));
} else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
ShouldAKA));
}
return QC.apply(Context, QT);

View File

@ -506,6 +506,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
return TPResult::Error();
if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
Tok.is(tok::ampamp) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
// ptr-operator
ConsumeToken();
@ -608,6 +609,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::l_square:
case tok::l_paren:
case tok::amp:
case tok::ampamp:
case tok::star:
case tok::plus:
case tok::plusplus:

View File

@ -2575,9 +2575,7 @@ static void TryReferenceInitialization(Sema &S,
// - Otherwise, the reference shall be an lvalue reference to a
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference and the initializer expression shall
// be an rvalue or have a function type.
// We handled the function type stuff above.
// shall be an rvalue reference.
if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) ||
(isRValueRef && InitCategory.isRValue()))) {
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)

View File

@ -1001,14 +1001,14 @@ QualType Sema::BuildPointerType(QualType T,
QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
SourceLocation Loc,
DeclarationName Entity) {
// C++0x [dcl.ref]p6:
// If a typedef (7.1.3), a type template-parameter (14.3.1), or a
// decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a
// type T, an attempt to create the type "lvalue reference to cv TR" creates
// the type "lvalue reference to T", while an attempt to create the type
// "rvalue reference to cv TR" creates the type TR.
bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>();
// C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
// reference to a type T, and attempt to create the type "lvalue
// reference to cv TD" creates the type "lvalue reference to T".
// We use the qualifiers (restrict or none) of the original reference,
// not the new ones. This is consistent with GCC.
// C++ [dcl.ref]p4: There shall be no references to references.
//
// According to C++ DR 106, references to references are only
@ -1020,8 +1020,8 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
//
// Parser::ParseDeclaratorInternal diagnoses the case where
// references are written directly; here, we handle the
// collapsing of references-to-references as described in C++
// DR 106 and amended by C++ DR 540.
// collapsing of references-to-references as described in C++0x.
// DR 106 and 540 introduce reference-collapsing into C++98/03.
// C++ [dcl.ref]p1:
// A declarator that specifies the type "reference to cv void"

View File

@ -0,0 +1,38 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
// Test the C++0x-specific reference initialization rules, e.g., the
// rules for rvalue references.
template<typename T> T prvalue();
template<typename T> T&& xvalue();
template<typename T> T& lvalue();
struct Base { };
struct Derived : Base { };
struct HasArray {
int array[5];
};
int f(int);
void test_rvalue_refs() {
// If the initializer expression...
// - is an xvalue, class prvalue, array prvalue or function lvalue
// and "cv1 T1" is reference-compatible with "cv2 T2", or
// xvalue case
Base&& base0 = xvalue<Base>();
Base&& base1 = xvalue<Derived>();
int&& int0 = xvalue<int>();
// class prvalue case
Base&& base2 = prvalue<Base>();
Base&& base3 = prvalue<Derived>();
// FIXME: array prvalue case
// int (&&array0)[5] = HasArray().array;
// function lvalue case
int (&&function0)(int) = f;
}

View File

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template<typename T, typename U>
struct is_same {
static const bool value = false;
};
template<typename T>
struct is_same<T, T> {
static const bool value = true;
};
#define JOIN2(X,Y) X##Y
#define JOIN(X,Y) JOIN2(X,Y)
#define CHECK_EQUAL_TYPES(T1, T2) \
int JOIN(array,__LINE__)[is_same<T1, T2>::value? 1 : -1]
int i;
typedef int& LRI;
typedef int&& RRI;
typedef LRI& r1; CHECK_EQUAL_TYPES(r1, int&);
typedef const LRI& r2; CHECK_EQUAL_TYPES(r2, int&);
typedef const LRI&& r3; CHECK_EQUAL_TYPES(r3, int&);
typedef RRI& r4; CHECK_EQUAL_TYPES(r4, int&);
typedef RRI&& r5; CHECK_EQUAL_TYPES(r5, int&&);