diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 744a408e5796..c8b488e916ca 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'. Look through sugar for /// an instance of \. 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 3971cf60d5e0..23d61c0848b3 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 ">; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 0d0cd2e305be..8a93f7c5d1e3 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 { + 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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index adcf2ee00e75..fe1775e1eb5b 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(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; + // 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; - auto *Decomp = dyn_cast(D); - if (Decomp && !FirstDecompDeclaratorInGroup) - FirstDecompDeclaratorInGroup = Decomp; + 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 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; + // 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/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 8d789bdd5ad3..e9294d7f4362 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() { +#if __has_feature(cxx_trailing_return) auto a = 0, -#if __has_feature(cxx_trailing_return) - (*b)() -> void, -#endif + (*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/clang/test/CXX/drs/dr12xx.cpp b/clang/test/CXX/drs/dr12xx.cpp index 45b33f9d7daf..24039a1cd240 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 dr1295 { // dr1295: 4 +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 struct X { unsigned bitfield : 4; }; diff --git a/clang/test/CXX/drs/dr13xx.cpp b/clang/test/CXX/drs/dr13xx.cpp index f35ead7b5e94..a4223ffb9080 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 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/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index a0781458a852..ffc076512446 100644 --- a/clang/www/cxx_dr_status.html +++ b/clang/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