]> granicus.if.org Git - clang/commitdiff
Add some tests for reference-collapsing and referencing binding
authorDouglas Gregor <dgregor@apple.com>
Thu, 20 Jan 2011 16:08:06 +0000 (16:08 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 20 Jan 2011 16:08:06 +0000 (16:08 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123913 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ASTDiagnostic.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaType.cpp
test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp [new file with mode: 0644]
test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp [new file with mode: 0644]

index bd128f0514a5cf4178663e811151d0316798c52c..9870b515c67abe2f1dc284df3eddec6dbbfa8896 100644 (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);
index bec201ce23f6adae9f98b324db699156ce17555b..523054b2d8484c16f5bf7161e10c734a02396936 100644 (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:
index 9130603d560575d49ffaf1b0b4da5df13e502154..9593489b806374db25d26c174fd1348e26ee53e2 100644 (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)
index 9a75d3604d644bb462f98da308b8a5938133ce7c..40d3734836816ab6a17cee5bb520e8ffcc412aa4 100644 (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"
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
new file mode 100644 (file)
index 0000000..ef23050
--- /dev/null
@@ -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;
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
new file mode 100644 (file)
index 0000000..789cde7
--- /dev/null
@@ -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&&);