From: Richard Smith Date: Fri, 13 Jan 2017 02:22:01 +0000 (+0000) Subject: Implement DR1265 (wg21.link/cwg1265). X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bcbed8b11f98a6408166fb76d3c6a697440cb342;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291880 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 744a408e57..c8b488e916 100644 --- a/include/clang/AST/Type.h +++ b/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'. Look through sugar for /// an instance of \. This scheme will eventually /// replace the specific getAsXXXX methods above. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3971cf60d5..23d61c0848 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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 ">; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0d0cd2e305..8a93f7c5d1 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1560,60 +1560,73 @@ TagDecl *Type::getAsTagDecl() const { namespace { class GetContainedAutoVisitor : - public TypeVisitor { + public TypeVisitor { + bool Syntactic; public: - using TypeVisitor::Visit; - AutoType *Visit(QualType T) { + GetContainedAutoVisitor(bool Syntactic = false) : Syntactic(Syntactic) {} + + using TypeVisitor::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(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(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(GetContainedAutoVisitor().Visit(this)); +} + +bool Type::hasAutoForTrailingReturnType() const { + return dyn_cast_or_null( + GetContainedAutoVisitor(true).Visit(this)); } bool Type::hasIntegerRepresentation() const { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index adcf2ee00e..fe1775e1eb 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -11045,6 +11045,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { } } +static bool hasDeducedAuto(DeclaratorDecl *DD) { + auto *VD = dyn_cast(DD); + return VD && !VD->getType()->hasAutoForTrailingReturnType(); +} + Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group) { SmallVector 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(D); - if (DD && !FirstDeclaratorInGroup) - FirstDeclaratorInGroup = DD; - - auto *Decomp = dyn_cast(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(D)) { + if (!FirstDeclaratorInGroup) + FirstDeclaratorInGroup = DD; + if (!FirstDecompDeclaratorInGroup) + FirstDecompDeclaratorInGroup = dyn_cast(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 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(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(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/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp index 8d789bdd5a..e9294d7f43 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp +++ b/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 void h() { auto a = T(), *b = &a; #if __has_feature(cxx_decltype) diff --git a/test/CXX/drs/dr12xx.cpp b/test/CXX/drs/dr12xx.cpp index 45b33f9d7d..24039a1cd2 100644 --- a/test/CXX/drs/dr12xx.cpp +++ b/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/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp index f35ead7b5e..a4223ffb90 100644 --- a/test/CXX/drs/dr13xx.cpp +++ b/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 struct initializer_list { + const T *ptr; + size_t n; + initializer_list(const T*, size_t); + }; +} + namespace dr1315 { // dr1315: partial template struct A {}; template // 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' 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/www/cxx_dr_status.html b/www/cxx_dr_status.html index a0781458a8..ffc0765124 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -7405,7 +7405,7 @@ and POD class 1265 CD3 Mixed use of the auto specifier - Unknown + SVN 1266 @@ -7897,7 +7897,7 @@ and POD class 1347 CD3 Consistency of auto in multiple-declarator declarations - Unknown + Yes 1348