diff options
| -rw-r--r-- | clang/include/clang/AST/Type.h | 5 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 45 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 111 | ||||
| -rw-r--r-- | clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp | 35 | ||||
| -rw-r--r-- | clang/test/CXX/drs/dr12xx.cpp | 20 | ||||
| -rw-r--r-- | clang/test/CXX/drs/dr13xx.cpp | 19 | ||||
| -rw-r--r-- | clang/www/cxx_dr_status.html | 4 | 
8 files changed, 165 insertions, 78 deletions
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 744a408e579..c8b488e916c 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3971cf60d5e..23d61c0848b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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>">; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 0d0cd2e305b..8a93f7c5d1e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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 { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index adcf2ee00e7..fe1775e1eb5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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;        }      }    } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp index 8d789bdd5ad..e9294d7f436 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp @@ -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) diff --git a/clang/test/CXX/drs/dr12xx.cpp b/clang/test/CXX/drs/dr12xx.cpp index 45b33f9d7da..24039a1cd24 100644 --- a/clang/test/CXX/drs/dr12xx.cpp +++ b/clang/test/CXX/drs/dr12xx.cpp @@ -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;    }; diff --git a/clang/test/CXX/drs/dr13xx.cpp b/clang/test/CXX/drs/dr13xx.cpp index f35ead7b5e9..a4223ffb908 100644 --- a/clang/test/CXX/drs/dr13xx.cpp +++ b/clang/test/CXX/drs/dr13xx.cpp @@ -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; }; diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index a0781458a85..ffc07651244 100644 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -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>  | 

