From ef2cd8f8c30d48a27995c284cf480867dd8caaa5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 8 Feb 2017 20:39:08 +0000 Subject: [PATCH] More fixes for places where 'decltype(auto)' is permitted in the C++ grammar but makes no sense. llvm-svn: 294509 --- .../clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/include/clang/Sema/Sema.h | 3 +- clang/lib/Parse/ParseExprCXX.cpp | 3 +- clang/lib/Sema/SemaDeclCXX.cpp | 3 ++ clang/lib/Sema/SemaExprCXX.cpp | 31 ++++++++++------ .../SemaCXX/cxx1y-deduced-return-type.cpp | 35 +++++++++++++------ 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a25b959da658..be6922171ad7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1944,6 +1944,8 @@ def err_auto_bitfield : Error< "cannot pass bit-field as __auto_type initializer in C">; // C++1y decltype(auto) type +def err_decltype_auto_invalid : Error< + "'decltype(auto)' not allowed here">; def err_decltype_auto_cannot_be_combined : Error< "'decltype(auto)' cannot be combined with other type specifiers">; def err_decltype_auto_function_declarator_not_declaration : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0fb9a5d3d4d9..5b317b018a0a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4749,7 +4749,8 @@ public: ParsedType ObjectType, bool EnteringContext); - ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType); + ParsedType getDestructorTypeForDecltype(const DeclSpec &DS, + ParsedType ObjectType); // Checks that reinterpret casts don't have undefined behavior. void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index cb42a88e82bb..cb56ebb10430 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -2580,7 +2580,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { DeclSpec DS(AttrFactory); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); - if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { + if (ParsedType Type = + Actions.getDestructorTypeForDecltype(DS, ObjectType)) { Result.setDestructorName(TildeLoc, Type, EndLoc); return false; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f84d14cfa8cb..974e09f78d45 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3728,6 +3728,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD, BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); } else if (DS.getTypeSpecType() == TST_decltype) { BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + } else if (DS.getTypeSpecType() == TST_decltype_auto) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); + return true; } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); LookupParsedName(R, S, &SS); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index d51c50c58f3f..1185dacc227b 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -323,20 +323,31 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, return nullptr; } -ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { - if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) - return nullptr; - assert(DS.getTypeSpecType() == DeclSpec::TST_decltype - && "only get destructor types from declspecs"); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); - QualType SearchType = GetTypeFromParser(ObjectType); - if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) { - return ParsedType::make(T); - } +ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS, + ParsedType ObjectType) { + if (DS.getTypeSpecType() == DeclSpec::TST_error) + return nullptr; + if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); + return nullptr; + } + + assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && + "unexpected type in getDestructorType"); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + + // If we know the type of the object, check that the correct destructor + // type was named now; we can give better diagnostics this way. + QualType SearchType = GetTypeFromParser(ObjectType); + if (!SearchType.isNull() && !SearchType->isDependentType() && + !Context.hasSameUnqualifiedType(T, SearchType)) { Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; return nullptr; + } + + return ParsedType::make(T); } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, diff --git a/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp b/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp index a061cf4ddb7f..2592e7cf1055 100644 --- a/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp +++ b/clang/test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -385,16 +385,31 @@ namespace MemberTemplatesWithDeduction { } } -namespace NNS { - int n; - decltype(auto) i(); - decltype(n) j(); - struct X { - // We resolve a wording bug here: 'decltype(auto)::' should not be parsed - // as a nested-name-specifier. - friend decltype(auto) ::NNS::i(); - friend decltype(n) ::NNS::j(); // expected-error {{not a class}} - }; +// We resolve a wording bug here: 'decltype(auto)' should not be modeled as a +// decltype-specifier, just as a simple-type-specifier. All the extra places +// where a decltype-specifier can appear make no sense for 'decltype(auto)'. +namespace DecltypeAutoShouldNotBeADecltypeSpecifier { + namespace NNS { + int n; + decltype(auto) i(); + decltype(n) j(); + struct X { + friend decltype(auto) ::DecltypeAutoShouldNotBeADecltypeSpecifier::NNS::i(); + friend decltype(n) ::DecltypeAutoShouldNotBeADecltypeSpecifier::NNS::j(); // expected-error {{not a class}} + }; + } + + namespace Dtor { + struct A {}; + void f(A a) { a.~decltype(auto)(); } // expected-error {{'decltype(auto)' not allowed here}} + } + + namespace BaseClass { + struct A : decltype(auto) {}; // expected-error {{'decltype(auto)' not allowed here}} + struct B { + B() : decltype(auto)() {} // expected-error {{'decltype(auto)' not allowed here}} + }; + } } namespace CurrentInstantiation {