]> granicus.if.org Git - clang/commitdiff
Implement DR1265 (wg21.link/cwg1265).
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 13 Jan 2017 02:22:01 +0000 (02:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 13 Jan 2017 02:22:01 +0000 (02:22 +0000)
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.

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

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

index 744a408e57962ec4139f237b7239ae75a8814c03..c8b488e916ca5f364b8b2e8b52e5c39ad09c70d0 100644 (file)
@@ -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.
index 3971cf60d5e0dafe76e9f23b120aa760e2fe8d5e..23d61c0848b33358d132ca2704372628947f96d5 100644 (file)
@@ -1900,6 +1900,10 @@ def err_auto_new_deduction_failure : Error<
 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>">;
index 0d0cd2e305be2e27ad017e63a5062a167449341a..8a93f7c5d1e3c669be6fe26b1cd5173d5513f955 100644 (file)
@@ -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 {
index adcf2ee00e75646566fee5e76600c0bf5f7cfa41..fe1775e1eb5b0fde95a9acc187e485c969f1bd8a 100644 (file)
@@ -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::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
   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(MutableArrayRef<Decl *> Group) {
   //   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;
       }
     }
   }
index 8d789bdd5ad38355bca0e591bf549b4d432e27d7..e9294d7f4362c74aac9f1704d5ce72c5d6bb0d00 100644 (file)
@@ -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@-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)
index 45b33f9d7daf1a004060627aceb39c90fe0d9318..24039a1cd240399b01e87ccf4b1b44898e121320 100644 (file)
@@ -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;
   };
index f35ead7b5e94ade61517da1b2ba4d8b740c8761b..a4223ffb90802d075954aea3db4ee9e46cc5b9e6 100644 (file)
@@ -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; };
index a0781458a852296500bd7b0a1d1ca9b61a571fa2..ffc076512446088cdb96a21ab7af13b7925a2248 100644 (file)
@@ -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>