r291880 - Implement DR1265 (wg21.link/cwg1265).

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 12 18:22:02 PST 2017


Author: rsmith
Date: Thu Jan 12 20:22:01 2017
New Revision: 291880

URL: http://llvm.org/viewvc/llvm-project?rev=291880&view=rev
Log:
Implement DR1265 (wg21.link/cwg1265).

Diasllow a declaration using the 'auto' type specifier from using two different
meanings of it at once, or from declaring multiple functions with deduced
return types or introducing multiple trailing return types.

The standard does not technically disallow the multiple trailing return types
case if all the declarators declare variables (such as function pointers with
trailing return types), but we disallow that too, following the clear intent.

Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
    cfe/trunk/test/CXX/drs/dr12xx.cpp
    cfe/trunk/test/CXX/drs/dr13xx.cpp
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Jan 12 20:22:01 2017
@@ -1867,6 +1867,11 @@ public:
   /// types, but not through decltype or typedefs.
   AutoType *getContainedAutoType() const;
 
+  /// Determine whether this type was written with a leading 'auto'
+  /// corresponding to a trailing return type (possibly for a nested
+  /// function type within a pointer to function type or similar).
+  bool hasAutoForTrailingReturnType() const;
+
   /// Member-template getAs<specific type>'.  Look through sugar for
   /// an instance of \<specific type>.   This scheme will eventually
   /// replace the specific getAsXXXX methods above.

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 12 20:22:01 2017
@@ -1900,6 +1900,10 @@ def err_auto_new_deduction_failure : Err
 def err_auto_different_deductions : Error<
   "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration "
   "of %2 and deduced as %3 in declaration of %4">;
+def err_auto_non_deduced_not_alone : Error<
+  "%select{function with deduced return type|"
+  "declaration with trailing return type}0 "
+  "must be the only declaration in its group">;
 def err_implied_std_initializer_list_not_found : Error<
   "cannot deduce type of initializer list because std::initializer_list was "
   "not found; include <initializer_list>">;

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Thu Jan 12 20:22:01 2017
@@ -1560,60 +1560,73 @@ TagDecl *Type::getAsTagDecl() const {
 
 namespace {
   class GetContainedAutoVisitor :
-    public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
+    public TypeVisitor<GetContainedAutoVisitor, Type*> {
+    bool Syntactic;
   public:
-    using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
-    AutoType *Visit(QualType T) {
+    GetContainedAutoVisitor(bool Syntactic = false) : Syntactic(Syntactic) {}
+
+    using TypeVisitor<GetContainedAutoVisitor, Type*>::Visit;
+    Type *Visit(QualType T) {
       if (T.isNull())
         return nullptr;
       return Visit(T.getTypePtr());
     }
 
     // The 'auto' type itself.
-    AutoType *VisitAutoType(const AutoType *AT) {
+    Type *VisitAutoType(const AutoType *AT) {
       return const_cast<AutoType*>(AT);
     }
 
     // Only these types can contain the desired 'auto' type.
-    AutoType *VisitPointerType(const PointerType *T) {
+    Type *VisitPointerType(const PointerType *T) {
       return Visit(T->getPointeeType());
     }
-    AutoType *VisitBlockPointerType(const BlockPointerType *T) {
+    Type *VisitBlockPointerType(const BlockPointerType *T) {
       return Visit(T->getPointeeType());
     }
-    AutoType *VisitReferenceType(const ReferenceType *T) {
+    Type *VisitReferenceType(const ReferenceType *T) {
       return Visit(T->getPointeeTypeAsWritten());
     }
-    AutoType *VisitMemberPointerType(const MemberPointerType *T) {
+    Type *VisitMemberPointerType(const MemberPointerType *T) {
       return Visit(T->getPointeeType());
     }
-    AutoType *VisitArrayType(const ArrayType *T) {
+    Type *VisitArrayType(const ArrayType *T) {
       return Visit(T->getElementType());
     }
-    AutoType *VisitDependentSizedExtVectorType(
+    Type *VisitDependentSizedExtVectorType(
       const DependentSizedExtVectorType *T) {
       return Visit(T->getElementType());
     }
-    AutoType *VisitVectorType(const VectorType *T) {
+    Type *VisitVectorType(const VectorType *T) {
       return Visit(T->getElementType());
     }
-    AutoType *VisitFunctionType(const FunctionType *T) {
+    Type *VisitFunctionProtoType(const FunctionProtoType *T) {
+      if (Syntactic && T->hasTrailingReturn())
+        return const_cast<FunctionProtoType*>(T);
+      return VisitFunctionType(T);
+    }
+    Type *VisitFunctionType(const FunctionType *T) {
       return Visit(T->getReturnType());
     }
-    AutoType *VisitParenType(const ParenType *T) {
+    Type *VisitParenType(const ParenType *T) {
       return Visit(T->getInnerType());
     }
-    AutoType *VisitAttributedType(const AttributedType *T) {
+    Type *VisitAttributedType(const AttributedType *T) {
       return Visit(T->getModifiedType());
     }
-    AutoType *VisitAdjustedType(const AdjustedType *T) {
+    Type *VisitAdjustedType(const AdjustedType *T) {
       return Visit(T->getOriginalType());
     }
   };
 }
 
 AutoType *Type::getContainedAutoType() const {
-  return GetContainedAutoVisitor().Visit(this);
+  return cast_or_null<AutoType>(GetContainedAutoVisitor().Visit(this));
+}
+
+bool Type::hasAutoForTrailingReturnType() const {
+  return dyn_cast_or_null<FunctionType>(
+      GetContainedAutoVisitor(true).Visit(this));
 }
 
 bool Type::hasIntegerRepresentation() const {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 12 20:22:01 2017
@@ -11045,6 +11045,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl
   }
 }
 
+static bool hasDeducedAuto(DeclaratorDecl *DD) {
+  auto *VD = dyn_cast<VarDecl>(DD);
+  return VD && !VD->getType()->hasAutoForTrailingReturnType();
+}
+
 Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
                                                    ArrayRef<Decl *> Group) {
   SmallVector<Decl*, 8> Decls;
@@ -11055,29 +11060,46 @@ Sema::DeclGroupPtrTy Sema::FinalizeDecla
   DeclaratorDecl *FirstDeclaratorInGroup = nullptr;
   DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr;
   bool DiagnosedMultipleDecomps = false;
+  DeclaratorDecl *FirstNonDeducedAutoInGroup = nullptr;
+  bool DiagnosedNonDeducedAuto = false;
 
   for (unsigned i = 0, e = Group.size(); i != e; ++i) {
     if (Decl *D = Group[i]) {
-      auto *DD = dyn_cast<DeclaratorDecl>(D);
-      if (DD && !FirstDeclaratorInGroup)
-        FirstDeclaratorInGroup = DD;
-
-      auto *Decomp = dyn_cast<DecompositionDecl>(D);
-      if (Decomp && !FirstDecompDeclaratorInGroup)
-        FirstDecompDeclaratorInGroup = Decomp;
-
-      // A decomposition declaration cannot be combined with any other
-      // declaration in the same group.
-      auto *OtherDD = FirstDeclaratorInGroup;
-      if (OtherDD == FirstDecompDeclaratorInGroup)
-        OtherDD = DD;
-      if (OtherDD && FirstDecompDeclaratorInGroup &&
-          OtherDD != FirstDecompDeclaratorInGroup &&
-          !DiagnosedMultipleDecomps) {
-        Diag(FirstDecompDeclaratorInGroup->getLocation(),
-             diag::err_decomp_decl_not_alone)
-          << OtherDD->getSourceRange();
-        DiagnosedMultipleDecomps = true;
+      // For declarators, there are some additional syntactic-ish checks we need
+      // to perform.
+      if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
+        if (!FirstDeclaratorInGroup)
+          FirstDeclaratorInGroup = DD;
+        if (!FirstDecompDeclaratorInGroup)
+          FirstDecompDeclaratorInGroup = dyn_cast<DecompositionDecl>(D);
+        if (!FirstNonDeducedAutoInGroup && DS.containsPlaceholderType() &&
+            !hasDeducedAuto(DD))
+          FirstNonDeducedAutoInGroup = DD;
+
+        if (FirstDeclaratorInGroup != DD) {
+          // A decomposition declaration cannot be combined with any other
+          // declaration in the same group.
+          if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) {
+            Diag(FirstDecompDeclaratorInGroup->getLocation(),
+                 diag::err_decomp_decl_not_alone)
+                << FirstDeclaratorInGroup->getSourceRange()
+                << DD->getSourceRange();
+            DiagnosedMultipleDecomps = true;
+          }
+
+          // A declarator that uses 'auto' in any way other than to declare a
+          // variable with a deduced type cannot be combined with any other
+          // declarator in the same group.
+          if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) {
+            Diag(FirstNonDeducedAutoInGroup->getLocation(),
+                 diag::err_auto_non_deduced_not_alone)
+                << FirstNonDeducedAutoInGroup->getType()
+                       ->hasAutoForTrailingReturnType()
+                << FirstDeclaratorInGroup->getSourceRange()
+                << DD->getSourceRange();
+            DiagnosedNonDeducedAuto = true;
+          }
+        }
       }
 
       Decls.push_back(D);
@@ -11105,38 +11127,27 @@ Sema::BuildDeclaratorGroup(MutableArrayR
   //   deduction, the program is ill-formed.
   if (Group.size() > 1) {
     QualType Deduced;
-    CanQualType DeducedCanon;
     VarDecl *DeducedDecl = nullptr;
     for (unsigned i = 0, e = Group.size(); i != e; ++i) {
-      if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
-        AutoType *AT = D->getType()->getContainedAutoType();
-        // FIXME: DR1265: if we have a function pointer declaration, we can have
-        // an 'auto' from a trailing return type. In that case, the return type
-        // must match the various other uses of 'auto'.
-        if (!AT)
-          continue;
-        // Don't reissue diagnostics when instantiating a template.
-        if (D->isInvalidDecl())
-          break;
-        QualType U = AT->getDeducedType();
-        if (!U.isNull()) {
-          CanQualType UCanon = Context.getCanonicalType(U);
-          if (Deduced.isNull()) {
-            Deduced = U;
-            DeducedCanon = UCanon;
-            DeducedDecl = D;
-          } else if (DeducedCanon != UCanon) {
-            Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
-                 diag::err_auto_different_deductions)
-              << (unsigned)AT->getKeyword()
-              << Deduced << DeducedDecl->getDeclName()
-              << U << D->getDeclName()
-              << DeducedDecl->getInit()->getSourceRange()
-              << D->getInit()->getSourceRange();
-            D->setInvalidDecl();
-            break;
-          }
-        }
+      VarDecl *D = dyn_cast<VarDecl>(Group[i]);
+      if (!D || D->isInvalidDecl())
+        break;
+      AutoType *AT = D->getType()->getContainedAutoType();
+      if (!AT || AT->getDeducedType().isNull())
+        continue;
+      if (Deduced.isNull()) {
+        Deduced = AT->getDeducedType();
+        DeducedDecl = D;
+      } else if (!Context.hasSameType(AT->getDeducedType(), Deduced)) {
+        Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+             diag::err_auto_different_deductions)
+          << (unsigned)AT->getKeyword()
+          << Deduced << DeducedDecl->getDeclName()
+          << AT->getDeducedType() << D->getDeclName()
+          << DeducedDecl->getInit()->getSourceRange()
+          << D->getInit()->getSourceRange();
+        D->setInvalidDecl();
+        break;
       }
     }
   }

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp Thu Jan 12 20:22:01 2017
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
 void f() {
@@ -19,22 +20,42 @@ void f() {
 }
 
 void g() {
-  auto a = 0,
 #if __has_feature(cxx_trailing_return)
-       (*b)() -> void,
-#endif
+  auto a = 0,
+       (*b)() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
        c = 0;
-  auto d = 0, // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
-#if __has_feature(cxx_trailing_return)
-       (*e)() -> void,
-#endif
+  auto d = 0,
+       e() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
        f = 0.0;
+  auto x() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+       y() -> void;
+#endif
 
 #if __has_feature(cxx_decltype)
   auto g = 0ull, h = decltype(g)(0);
 #endif
 }
 
+#if __has_feature(cxx_trailing_return)
+int F();
+auto p = 0, (*q)() -> auto = F; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+  #if __cplusplus < 201402L
+  // expected-error at -2 {{'auto' not allowed in function return type}}
+  #endif
+#endif
+
+#if __cplusplus >= 201402L
+namespace DeducedReturnType {
+  auto a = 0,
+       b(), // expected-error {{function with deduced return type must be the only declaration in its group}}
+       c = 0.0;
+  auto d(), // expected-error {{function with deduced return type must be the only declaration in its group}}
+       e = 1;
+  auto f(), // expected-error {{function with deduced return type must be the only declaration in its group}}
+       g();
+}
+#endif
+
 template<typename T> void h() {
   auto a = T(), *b = &a;
 #if __has_feature(cxx_decltype)

Modified: cfe/trunk/test/CXX/drs/dr12xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr12xx.cpp?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr12xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr12xx.cpp Thu Jan 12 20:22:01 2017
@@ -14,7 +14,7 @@ namespace dr1213 { // dr1213: 4
 #endif
 }
 
-namespace dr1250 {  // dr1250: 3.9
+namespace dr1250 { // dr1250: 3.9
 struct Incomplete;
 
 struct Base {
@@ -24,9 +24,23 @@ struct Base {
 struct Derived : Base {
   virtual Incomplete *meow();
 };
-} // dr1250
+}
+
+namespace dr1265 { // dr1265: 5
+#if __cplusplus >= 201103L
+  auto a = 0, b() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+  auto b() -> int, d = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+  auto e() -> int, f() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+#endif
+
+#if __cplusplus >= 201402L
+  auto g(), h = 0; // expected-error {{function with deduced return type must be the only declaration in its group}}
+  auto i = 0, j(); // expected-error {{function with deduced return type must be the only declaration in its group}}
+  auto k(), l(); // expected-error {{function with deduced return type must be the only declaration in its group}}
+#endif
+}
 
-namespace dr1295 {  // dr1295: 4
+namespace dr1295 { // dr1295: 4
   struct X {
     unsigned bitfield : 4;
   };

Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr13xx.cpp Thu Jan 12 20:22:01 2017
@@ -3,6 +3,16 @@
 // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
+__extension__ typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+  template<typename T> struct initializer_list {
+    const T *ptr;
+    size_t n;
+    initializer_list(const T*, size_t);
+  };
+}
+
 namespace dr1315 { // dr1315: partial
   template <int I, int J> struct A {};
   template <int I> // expected-note {{non-deducible template parameter 'I'}}
@@ -159,6 +169,15 @@ namespace dr1346 { // dr1346: 3.5
 #endif
 }
 
+namespace dr1347 { // dr1347: yes
+  auto x = 5, *y = &x; // expected-error 0-1{{extension}}
+  auto z = y, *q = y; // expected-error {{'auto' deduced as 'int *' in declaration of 'z' and deduced as 'int' in declaration of 'q'}} expected-error 0-1{{extension}}
+#if __cplusplus >= 201103L
+  auto a = 5, b = {1, 2}; // expected-error {{'auto' deduced as 'int' in declaration of 'a' and deduced as 'std::initializer_list<int>' in declaration of 'b'}}
+  auto (*fp)(int) -> int, i = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+#endif
+}
+
 namespace dr1359 { // dr1359: 3.5
 #if __cplusplus >= 201103L
   union A { constexpr A() = default; };

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=291880&r1=291879&r2=291880&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Thu Jan 12 20:22:01 2017
@@ -7405,7 +7405,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1265">1265</a></td>
     <td>CD3</td>
     <td>Mixed use of the <TT>auto</TT> specifier</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr class="open" id="1266">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1266">1266</a></td>
@@ -7897,7 +7897,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1347">1347</a></td>
     <td>CD3</td>
     <td>Consistency of <TT>auto</TT> in multiple-declarator declarations</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="full" align="center">Yes</td>
   </tr>
   <tr class="open" id="1348">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1348">1348</a></td>




More information about the cfe-commits mailing list