Rakete1111 updated this revision to Diff 178289. Rakete1111 added a comment.
@rsmith do you have any more comments? ping/rebase. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D53847/new/ https://reviews.llvm.org/D53847 Files: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h include/clang/Sema/DeclSpec.h include/clang/Sema/Sema.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTemplate.cpp lib/Parse/ParseTentative.cpp lib/Parse/Parser.cpp lib/Sema/DeclSpec.cpp lib/Sema/Sema.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/CXX/drs/dr1xx.cpp test/CXX/drs/dr2xx.cpp test/CXX/drs/dr4xx.cpp test/CXX/drs/dr5xx.cpp test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp test/FixIt/fixit.cpp test/Parser/cxx-member-initializers.cpp test/Parser/editor-placeholder-recovery.cpp test/SemaCXX/MicrosoftCompatibility.cpp test/SemaCXX/MicrosoftExtensions.cpp test/SemaCXX/MicrosoftSuper.cpp test/SemaCXX/unknown-type-name.cpp
Index: test/SemaCXX/unknown-type-name.cpp =================================================================== --- test/SemaCXX/unknown-type-name.cpp +++ test/SemaCXX/unknown-type-name.cpp @@ -36,15 +36,15 @@ static int n; static type m; - static int h(T::type, int); // expected-error{{missing 'typename'}} - static int h(T::type x, char); // expected-error{{missing 'typename'}} + static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}} + static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}} }; template<typename T> -A<T>::type g(T t) { return t; } // expected-error{{missing 'typename'}} +A<T>::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}} template<typename T> -A<T>::type A<T>::f() { return type(); } // expected-error{{missing 'typename'}} +A<T>::type A<T>::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}} template<typename T> void f(T::type) { } // expected-error{{missing 'typename'}} @@ -72,9 +72,7 @@ int *p; -// FIXME: We should assume that 'undeclared' is a type, not a parameter name -// here, and produce an 'unknown type name' diagnostic instead. -int f1(undeclared, int); // expected-error{{requires a type specifier}} +int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}} int f2(undeclared, 0); // expected-error{{undeclared identifier}} @@ -86,11 +84,11 @@ template<typename T> int A<T>::n(T::value); // ok template<typename T> -A<T>::type // expected-error{{missing 'typename'}} +A<T>::type // expected-warning {{implicit 'typename' is a C++2a extension}} A<T>::m(T::value, 0); // ok -template<typename T> int A<T>::h(T::type, int) {} // expected-error{{missing 'typename'}} -template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing 'typename'}} +template<typename T> int A<T>::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}} +template<typename T> int A<T>::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}} template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}} template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}} @@ -118,4 +116,5 @@ // FIXME: We know which type specifier should have been specified here. Provide // a fix-it to add 'typename A<T>::type' template<typename T> -A<T>::g() { } // expected-error{{requires a type specifier}} +A<T>::g() { } // expected-error{{expected unqualified-id}} +// expected-warning@-1{{implicit 'typename' is a C++2a extension}} Index: test/SemaCXX/MicrosoftSuper.cpp =================================================================== --- test/SemaCXX/MicrosoftSuper.cpp +++ test/SemaCXX/MicrosoftSuper.cpp @@ -108,8 +108,8 @@ typename __super::XXX a; typedef typename __super::XXX b; - __super::XXX c; // expected-error {{missing 'typename'}} - typedef __super::XXX d; // expected-error {{missing 'typename'}} + __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}} + typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}} void foo() { typename __super::XXX e; @@ -127,8 +127,8 @@ typename __super::XXX a; typedef typename __super::XXX b; - __super::XXX c; // expected-error {{missing 'typename'}} - typedef __super::XXX d; // expected-error {{missing 'typename'}} + __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}} + typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}} void foo() { typename __super::XXX e; Index: test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- test/SemaCXX/MicrosoftExtensions.cpp +++ test/SemaCXX/MicrosoftExtensions.cpp @@ -526,7 +526,7 @@ namespace PR32750 { template<typename T> struct A {}; -template<typename T> struct B : A<A<T>> { A<T>::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name 'A<T>::C::D'}} +template<typename T> struct B : A<A<T>> { A<T>::C::D d; }; // expected-warning {{implicit 'typename' is a C++2a extension}} } #else Index: test/SemaCXX/MicrosoftCompatibility.cpp =================================================================== --- test/SemaCXX/MicrosoftCompatibility.cpp +++ test/SemaCXX/MicrosoftCompatibility.cpp @@ -199,14 +199,14 @@ typedef B<U> Base2; typedef A<U> Base3; - A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}} - Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}} + A<T>::TYPE a1; // expected-warning {{implicit 'typename' is a C++2a extension}} + Base1::TYPE a2; // expected-warning {{implicit 'typename' is a C++2a extension}} - B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}} - Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}} + B<U>::TYPE a3; // expected-warning {{implicit 'typename' is a C++2a extension}} + Base2::TYPE a4; // expected-warning {{implicit 'typename' is a C++2a extension}} - A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}} - Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}} + A<U>::TYPE a5; // expected-warning {{implicit 'typename' is a C++2a extension}} + Base3::TYPE a6; // expected-warning {{implicit 'typename' is a C++2a extension}} }; class D { @@ -215,9 +215,9 @@ }; template <class T> -void function_missing_typename(const T::Type param)// expected-warning {{missing 'typename' prior to dependent type name}} +void function_missing_typename(const T::Type param)// expected-warning {{missing 'typename'}} { - const T::Type var = 2; // expected-warning {{missing 'typename' prior to dependent type name}} + const T::Type var = 2; // expected-warning {{missing 'typename'}} } template void function_missing_typename<D>(const D::Type param); Index: test/Parser/editor-placeholder-recovery.cpp =================================================================== --- test/Parser/editor-placeholder-recovery.cpp +++ test/Parser/editor-placeholder-recovery.cpp @@ -64,7 +64,7 @@ } } -void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} expected-error {{C++ requires a type specifier for all declarations}} +void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} #ifndef SUPPRESS // expected-error@-2 {{editor placeholder in source file}} #endif Index: test/Parser/cxx-member-initializers.cpp =================================================================== --- test/Parser/cxx-member-initializers.cpp +++ test/Parser/cxx-member-initializers.cpp @@ -103,5 +103,5 @@ void l(int x = C<int, C<int, int>::C1>().f()) {} // This isn't, but it shouldn't crash. The diagnostics don't matter much. - void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{expected a type}} + void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{type name requires a specifier or qualifier}} }; Index: test/FixIt/fixit.cpp =================================================================== --- test/FixIt/fixit.cpp +++ test/FixIt/fixit.cpp @@ -211,7 +211,7 @@ template<class T> struct Mystery; template<class T> typedef Mystery<T>::type getMysteriousThing() { // \ expected-error {{function definition declared 'typedef'}} \ - expected-error {{missing 'typename' prior to dependent}} + expected-warning {{implicit 'typename' is a C++2a extension}} return Mystery<T>::get(); } Index: test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp =================================================================== --- test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp +++ test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp @@ -17,7 +17,7 @@ template<class T> struct A<A<A<T>>> { struct C {}; - B<B<T>>::C bc; // expected-error {{missing 'typename'}} + B<B<T>>::C bc; // expected-warning {{implicit 'typename' is a C++2a extension}} }; } Index: test/CXX/drs/dr5xx.cpp =================================================================== --- test/CXX/drs/dr5xx.cpp +++ test/CXX/drs/dr5xx.cpp @@ -228,8 +228,8 @@ template<int N> struct X { typedef int type; X<N>::type v1; - X<(N)>::type v2; // expected-error {{missing 'typename'}} - X<+N>::type v3; // expected-error {{missing 'typename'}} + X<(N)>::type v2; // expected-error {{implicit 'typename' is a C++2a extension}} + X<+N>::type v3; // expected-error {{implicit 'typename' is a C++2a extension}} }; } Index: test/CXX/drs/dr4xx.cpp =================================================================== --- test/CXX/drs/dr4xx.cpp +++ test/CXX/drs/dr4xx.cpp @@ -173,7 +173,7 @@ B b1; A::B b2; A<T>::B b3; - A<T*>::B b4; // expected-error {{missing 'typename'}} + A<T*>::B b4; // expected-error {{implicit 'typename' is a C++2a extension}} }; } Index: test/CXX/drs/dr2xx.cpp =================================================================== --- test/CXX/drs/dr2xx.cpp +++ test/CXX/drs/dr2xx.cpp @@ -242,7 +242,7 @@ typedef int type; A::type a; A<T>::type b; - A<T*>::type c; // expected-error {{missing 'typename'}} + A<T*>::type c; // expected-error {{implicit 'typename' is a C++2a extension}} ::dr224::example1::A<T>::type d; class B { @@ -250,12 +250,12 @@ A::type a; A<T>::type b; - A<T*>::type c; // expected-error {{missing 'typename'}} + A<T*>::type c; // expected-error {{implicit 'typename' is a C++2a extension}} ::dr224::example1::A<T>::type d; B::type e; A<T>::B::type f; - A<T*>::B::type g; // expected-error {{missing 'typename'}} + A<T*>::B::type g; // expected-error {{implicit 'typename' is a C++2a extension}} typename A<T*>::B::type h; }; }; @@ -263,21 +263,21 @@ template <class T> class A<T*> { typedef int type; A<T*>::type a; - A<T>::type b; // expected-error {{missing 'typename'}} + A<T>::type b; // expected-error {{implicit 'typename' is a C++2a extension}} }; template <class T1, class T2, int I> struct B { typedef int type; B<T1, T2, I>::type b1; - B<T2, T1, I>::type b2; // expected-error {{missing 'typename'}} + B<T2, T1, I>::type b2; // expected-error {{implicit 'typename' is a C++2a extension}} typedef T1 my_T1; static const int my_I = I; static const int my_I2 = I+0; static const int my_I3 = my_I; - B<my_T1, T2, my_I>::type b3; // FIXME: expected-error {{missing 'typename'}} - B<my_T1, T2, my_I2>::type b4; // expected-error {{missing 'typename'}} - B<my_T1, T2, my_I3>::type b5; // FIXME: expected-error {{missing 'typename'}} + B<my_T1, T2, my_I>::type b3; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}} + B<my_T1, T2, my_I2>::type b4; // expected-error {{implicit 'typename' is a C++2a extension}} + B<my_T1, T2, my_I3>::type b5; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}} }; } @@ -285,10 +285,10 @@ template <int, typename T> struct X { typedef T type; }; template <class T> class A { static const int i = 5; - X<i, int>::type w; // FIXME: expected-error {{missing 'typename'}} - X<A::i, char>::type x; // FIXME: expected-error {{missing 'typename'}} - X<A<T>::i, double>::type y; // FIXME: expected-error {{missing 'typename'}} - X<A<T*>::i, long>::type z; // expected-error {{missing 'typename'}} + X<i, int>::type w; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}} + X<A::i, char>::type x; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}} + X<A<T>::i, double>::type y; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}} + X<A<T*>::i, long>::type z; // expected-error {{implicit 'typename' is a C++2a extension}} int f(); }; template <class T> int A<T>::f() { Index: test/CXX/drs/dr1xx.cpp =================================================================== --- test/CXX/drs/dr1xx.cpp +++ test/CXX/drs/dr1xx.cpp @@ -58,7 +58,7 @@ namespace dr108 { // dr108: yes template<typename T> struct A { struct B { typedef int X; }; - B::X x; // expected-error {{missing 'typename'}} + B::X x; // expected-error {{implicit 'typename' is a C++2a extension}} struct C : B { X x; }; // expected-error {{unknown type name}} }; template<> struct A<int>::B { int X; }; Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -9438,10 +9438,11 @@ return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } -TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, const IdentifierInfo &II, - SourceLocation IdLoc) { +TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, + const IdentifierInfo &II, + SourceLocation IdLoc, + bool IsImplicitTypename) { if (SS.isInvalid()) return true; @@ -9453,8 +9454,9 @@ << FixItHint::CreateRemoval(TypenameLoc); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); - QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, - TypenameLoc, QualifierLoc, II, IdLoc); + QualType T = CheckTypenameType( + TypenameLoc.isValid() || IsImplicitTypename ? ETK_Typename : ETK_None, + TypenameLoc, QualifierLoc, II, IdLoc); if (T.isNull()) return true; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -281,6 +281,7 @@ bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, bool IsClassTemplateDeductionContext, + bool AllowImplicitTypename, IdentifierInfo **CorrectedII) { // FIXME: Consider allowing this outside C++1z mode as an extension. bool AllowDeducedTemplate = IsClassTemplateDeductionContext && @@ -307,17 +308,32 @@ // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. - if (!isClassName && !IsCtorOrDtorName) + // In C++2a, in several contexts a 'typename' is not required. Also + // allow this as an extension. + if (!AllowImplicitTypename && !isClassName && !IsCtorOrDtorName) return nullptr; + bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName; + if (IsImplicitTypename) { + SourceLocation QualifiedLoc = SS->getRange().getBegin(); + if (getLangOpts().CPlusPlus2a) + Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename); + else + Diag(QualifiedLoc, diag::ext_implicit_typename) + << SS->getScopeRep() << II.getName() + << FixItHint::CreateInsertion(QualifiedLoc, "typename "); + } // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. if (WantNontrivialTypeSourceInfo) - return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); + return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc, + IsImplicitTypename) + .get(); NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); - QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, - II, NameLoc); + QualType T = + CheckTypenameType(IsImplicitTypename ? ETK_Typename : ETK_None, + SourceLocation(), QualifierLoc, II, NameLoc); return ParsedType::make(T); } @@ -5434,7 +5450,12 @@ LookupName(Previous, S, CreateBuiltins); } else { // Something like "int foo::x;" - LookupQualifiedName(Previous, DC); + if (D.hasPrevLookupResult()) { + Previous = std::move(D.getPrevLookupResult()); + D.setPrevLookupResult(nullptr); + } + else + LookupQualifiedName(Previous, DC); // C++ [dcl.meaning]p1: // When the declarator-id is qualified, the declaration shall refer to a Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -2006,3 +2006,28 @@ return checkOpenCLDisabledTypeOrDecl(&D, E.getBeginLoc(), FnName, OpenCLDeclExtMap, 1, D.getSourceRange()); } + +bool Sema::isDeclaratorFunctionLike(Declarator &D) { + assert(D.getCXXScopeSpec().isSet() && + "can only be called for qualified names"); + LookupResult LR(*this, D.getIdentifier(), D.getBeginLoc(), LookupOrdinaryName, + forRedeclarationInCurContext()); + DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), + !D.getDeclSpec().isFriendSpecified()); + if (!DC) + return false; + + LookupQualifiedName(LR, DC); + bool Result = std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(Dcl)) { + ND = ND->getUnderlyingDecl(); + return isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) || + isa<UsingDecl>(ND); + } + return false; + }); + + + D.setPrevLookupResult(new LookupResult(std::move(LR))); + return Result; +} Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -19,6 +19,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -1500,7 +1500,8 @@ return ANK_Error; if (Tok.isNot(tok::identifier) || SS.isInvalid()) { - if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation)) + if (TryAnnotateTypeOrScopeTokenAfterScopeSpec( + SS, !WasScopeAnnotation, /*AllowImplicitTypename=*/false)) return ANK_Error; return ANK_Unresolved; } @@ -1510,10 +1511,11 @@ // FIXME: Move the tentative declaration logic into ClassifyName so we can // typo-correct to tentatively-declared identifiers. - if (isTentativelyDeclared(Name)) { + if (isTentativelyDeclared(Name) && SS.isEmpty()) { // Identifier has been tentatively declared, and thus cannot be resolved as // an expression. Fall back to annotating it as a type. - if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation)) + if (TryAnnotateTypeOrScopeTokenAfterScopeSpec( + SS, !WasScopeAnnotation, /*AllowImplicitTypename=*/false)) return ANK_Error; return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl; } @@ -1651,7 +1653,7 @@ /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. -bool Parser::TryAnnotateTypeOrScopeToken() { +bool Parser::TryAnnotateTypeOrScopeToken(bool AllowImplicitTypename) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) || @@ -1668,7 +1670,7 @@ if (getLangOpts().MSVCCompat && NextToken().is(tok::kw_typedef)) { Token TypedefToken; PP.Lex(TypedefToken); - bool Result = TryAnnotateTypeOrScopeToken(); + bool Result = TryAnnotateTypeOrScopeToken(AllowImplicitTypename); PP.EnterToken(Tok); Tok = TypedefToken; if (!Result) @@ -1693,7 +1695,8 @@ Tok.is(tok::annot_decltype)) { // Attempt to recover by skipping the invalid 'typename' if (Tok.is(tok::annot_decltype) || - (!TryAnnotateTypeOrScopeToken() && Tok.isAnnotation())) { + (!TryAnnotateTypeOrScopeToken(AllowImplicitTypename) && + Tok.isAnnotation())) { unsigned DiagID = diag::err_expected_qualified_after_typename; // MS compatibility: MSVC permits using known types with typename. // e.g. "typedef typename T* pointer_type" @@ -1759,22 +1762,23 @@ if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext*/false)) return true; - return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation); + return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation, + AllowImplicitTypename); } /// Try to annotate a type or scope token, having already parsed an /// optional scope specifier. \p IsNewScope should be \c true unless the scope /// specifier was extracted from an existing tok::annot_cxxscope annotation. -bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, - bool IsNewScope) { +bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec( + CXXScopeSpec &SS, bool IsNewScope, bool AllowImplicitTypename) { if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. if (ParsedType Ty = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, NextToken().is(tok::period), nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo*/true, - /*IsClassTemplateDeductionContext*/true)) { + /*NonTrivialTypeSourceInfo*/ true, + /*IsClassTemplateDeductionContext*/ true, AllowImplicitTypename)) { SourceLocation BeginLoc = Tok.getLocation(); if (SS.isNotEmpty()) // it was a C++ qualified type name. BeginLoc = SS.getBeginLoc(); Index: lib/Parse/ParseTentative.cpp =================================================================== --- lib/Parse/ParseTentative.cpp +++ lib/Parse/ParseTentative.cpp @@ -1276,7 +1276,10 @@ /// Parser::TPResult Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, - bool *HasMissingTypename) { + bool *HasMissingTypename, + bool AllowImplicitTypename) { + const bool NoImplicitTypename = !HasMissingTypename || !AllowImplicitTypename; + switch (Tok.getKind()) { case tok::identifier: { // Check for need to substitute AltiVec __vector keyword @@ -1306,7 +1309,7 @@ // template template argument, we'll undo this when checking the // validity of the argument. if (getLangOpts().CPlusPlus17) { - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(NoImplicitTypename)) return TPResult::Error; if (Tok.isNot(tok::identifier)) break; @@ -1327,7 +1330,7 @@ // a missing 'typename' keyword. Don't use TryAnnotateName in this case, // since it will annotate as a primary expression, and we want to use the // "missing 'typename'" logic. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(!NoImplicitTypename)) return TPResult::Error; // If annotation failed, assume it's a non-type. // FIXME: If this happens due to an undeclared identifier, treat it as @@ -1343,7 +1346,7 @@ case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(/*AllowImplicitTypename=*/true)) return TPResult::Error; return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); @@ -1358,7 +1361,7 @@ case tok::kw_decltype: // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(!NoImplicitTypename)) return TPResult::Error; return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); @@ -1465,7 +1468,7 @@ case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed // We've already annotated a scope; try to annotate a type. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(!NoImplicitTypename)) return TPResult::Error; if (!Tok.is(tok::annot_typename)) { // If the next token is an identifier or a type qualifier, then this @@ -1759,7 +1762,8 @@ /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// -bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { +bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous, + bool AllowImplicitTypename) { // C++ 8.2p1: // The ambiguity arising from the similarity between a function-style cast and @@ -1774,7 +1778,9 @@ ConsumeParen(); bool InvalidAsDeclaration = false; - TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration); + TPResult TPR = TryParseParameterDeclarationClause( + &InvalidAsDeclaration, /*VersusTemplateArgument=*/false, + AllowImplicitTypename); if (TPR == TPResult::Ambiguous) { if (Tok.isNot(tok::r_paren)) TPR = TPResult::False; @@ -1820,7 +1826,8 @@ /// Parser::TPResult Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, - bool VersusTemplateArgument) { + bool VersusTemplateArgument, + bool AllowImplicitTypename) { if (Tok.is(tok::r_paren)) return TPResult::Ambiguous; @@ -1853,8 +1860,8 @@ // decl-specifier-seq // A parameter-declaration's initializer must be preceded by an '=', so // decl-specifier-seq '{' is not a parameter in C++11. - TPResult TPR = isCXXDeclarationSpecifier(TPResult::False, - InvalidAsDeclaration); + TPResult TPR = isCXXDeclarationSpecifier( + TPResult::False, InvalidAsDeclaration, AllowImplicitTypename); if (VersusTemplateArgument && TPR == TPResult::True) { // Consume the decl-specifier-seq. We have to look past it, since a Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -17,6 +17,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" using namespace clang; Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1352,7 +1352,8 @@ // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS); + ParseSpecifierQualifierList(DS, /*AccessSpecifier=*/AS_none, + DeclSpecContext::DSC_type_specifier); // Parse the abstract-declarator, if present. Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1200,7 +1200,8 @@ *Id, IdLoc, getCurScope(), &SS, /*IsClassName=*/true, false, nullptr, /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo=*/true, - /*IsClassTemplateDeductionContext*/ false, &CorrectedII); + /*IsClassTemplateDeductionContext*/ false, + /*AllowImplicitTypename=*/false, &CorrectedII); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -2627,6 +2627,9 @@ case tok::semi: // This looks like a variable or function declaration. The type is // probably missing. We're done parsing decl-specifiers. + // But only if we are not in a function prototype scope. + if (getCurScope()->isFunctionPrototypeScope()) + break; if (SS) AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); return false; @@ -2690,22 +2693,46 @@ /// DeclaratorContext enumerator values. Parser::DeclSpecContext Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) { - if (Context == DeclaratorContext::MemberContext) + switch (Context) { + case DeclaratorContext::MemberContext: return DeclSpecContext::DSC_class; - if (Context == DeclaratorContext::FileContext) + case DeclaratorContext::FileContext: return DeclSpecContext::DSC_top_level; - if (Context == DeclaratorContext::TemplateParamContext) + case DeclaratorContext::TemplateParamContext: return DeclSpecContext::DSC_template_param; - if (Context == DeclaratorContext::TemplateArgContext || - Context == DeclaratorContext::TemplateTypeArgContext) + case DeclaratorContext::TemplateArgContext: + return DeclSpecContext::DSC_template_arg; + case DeclaratorContext::TemplateTypeArgContext: return DeclSpecContext::DSC_template_type_arg; - if (Context == DeclaratorContext::TrailingReturnContext || - Context == DeclaratorContext::TrailingReturnVarContext) + case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::TrailingReturnVarContext: return DeclSpecContext::DSC_trailing; - if (Context == DeclaratorContext::AliasDeclContext || - Context == DeclaratorContext::AliasTemplateContext) + case DeclaratorContext::AliasDeclContext: + case DeclaratorContext::AliasTemplateContext: return DeclSpecContext::DSC_alias_declaration; - return DeclSpecContext::DSC_normal; + case DeclaratorContext::TypeNameContext: + return DeclSpecContext::DSC_type_specifier; + case DeclaratorContext::ConditionContext: + return DeclSpecContext::DSC_condition; + case DeclaratorContext::PrototypeContext: + case DeclaratorContext::ObjCResultContext: + case DeclaratorContext::ObjCParameterContext: + case DeclaratorContext::KNRTypeListContext: + case DeclaratorContext::FunctionalCastContext: + case DeclaratorContext::BlockContext: + case DeclaratorContext::ForContext: + case DeclaratorContext::InitStmtContext: + case DeclaratorContext::CXXNewContext: + case DeclaratorContext::CXXCatchContext: + case DeclaratorContext::ObjCCatchContext: + case DeclaratorContext::BlockLiteralContext: + case DeclaratorContext::LambdaExprContext: + case DeclaratorContext::LambdaExprParameterContext: + case DeclaratorContext::ConversionIdContext: + return DeclSpecContext::DSC_normal; + } + + llvm_unreachable("Missing DeclaratorContext case"); } /// ParseAlignArgument - Parse the argument to an alignment-specifier. @@ -2922,7 +2949,8 @@ const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSContext, - LateParsedAttrList *LateAttrs) { + LateParsedAttrList *LateAttrs, + bool AllowImplicitTypename) { if (DS.getSourceRange().isInvalid()) { // Start the range at the current token but make the end of the range // invalid. This will make the entire range invalid unless we successfully @@ -3110,12 +3138,13 @@ isConstructorDeclarator(/*Unqualified*/ false)) goto DoneWithDeclSpec; - ParsedType TypeRep = - Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), - getCurScope(), &SS, false, false, nullptr, - /*IsCtorOrDtorName=*/false, - /*WantNonTrivialSourceInfo=*/true, - isClassTemplateDeductionContext(DSContext)); + ParsedType TypeRep = Actions.getTypeName( + *Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, + false, false, nullptr, + /*IsCtorOrDtorName=*/false, + /*WantNonTrivialSourceInfo=*/true, + isClassTemplateDeductionContext(DSContext), + AllowImplicitTypename); // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and @@ -4814,7 +4843,7 @@ case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(/*AllowImplicitTypename=*/true)) return true; if (Tok.is(tok::identifier)) return false; @@ -5837,10 +5866,17 @@ // is not, the declarator has been fully parsed. bool IsAmbiguous = false; if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + bool AllowImplicitTypename = false; + if (D.getCXXScopeSpec().isSet()) + AllowImplicitTypename = Actions.isDeclaratorFunctionLike(D); + else if (D.getContext() == DeclaratorContext::MemberContext) + AllowImplicitTypename = true; + // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); - bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous); + bool IsFunctionDecl = + isCXXFunctionDeclarator(&IsAmbiguous, AllowImplicitTypename); TentativelyDeclaredIdentifiers.pop_back(); if (!IsFunctionDecl) break; @@ -6385,6 +6421,15 @@ ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { + + bool AllowImplicitTypename; + if (D.getContext() == DeclaratorContext::MemberContext || + D.getContext() == DeclaratorContext::LambdaExprContext) + AllowImplicitTypename = true; + else + AllowImplicitTypename = D.getCXXScopeSpec().isSet() && + D.isFunctionDeclaratorAFunctionDeclaration(); + do { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. @@ -6410,8 +6455,9 @@ // too much hassle. DS.takeAttributesFrom(FirstArgAttrs); - ParseDeclarationSpecifiers(DS); - + ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(), + AS_none, DeclSpecContext::DSC_normal, + /*LateAttrs=*/nullptr, AllowImplicitTypename); // Parse the declarator. This is "PrototypeContext" or // "LambdaExprParameterContext", because we must accept either Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1721,6 +1721,7 @@ bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, bool IsClassTemplateDeductionContext = true, + bool AllowImplicitTypename = false, IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); @@ -2062,6 +2063,10 @@ /// \c constexpr in C++11 or has an 'auto' return type in C++14). bool canSkipFunctionBody(Decl *D); + /// Determine whether \param D is function like (function or function + /// template) for parsing. + bool isDeclaratorFunctionLike(Declarator &D); + void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); @@ -6507,10 +6512,10 @@ /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param II the identifier we're retrieving (e.g., 'type' in the example). /// \param IdLoc the location of the identifier. - TypeResult - ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, const IdentifierInfo &II, - SourceLocation IdLoc); + TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, const IdentifierInfo &II, + SourceLocation IdLoc, + bool IsImplicitTypename = false); /// Called when the parser has parsed a C++ typename /// specifier that ends in a template-id, e.g., Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -40,6 +40,7 @@ class CXXRecordDecl; class TypeLoc; class LangOptions; + class LookupResult; class IdentifierInfo; class NamespaceAliasDecl; class NamespaceDecl; @@ -1818,6 +1819,9 @@ /// this declarator as a parameter pack. SourceLocation EllipsisLoc; + /// Lookup result of declarator, if any. + LookupResult *PrevLookupResult; + friend struct DeclaratorChunk; public: @@ -1827,7 +1831,8 @@ GroupingParens(false), FunctionDefinition(FDK_Declaration), Redeclaration(false), Extension(false), ObjCIvar(false), ObjCWeakProperty(false), InlineStorageUsed(false), - Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr) {} + Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr), + PrevLookupResult(nullptr) {} ~Declarator() { clear(); @@ -2466,6 +2471,17 @@ void setRedeclaration(bool Val) { Redeclaration = Val; } bool isRedeclaration() const { return Redeclaration; } + + void setPrevLookupResult(LookupResult *LR) { PrevLookupResult = LR; } + LookupResult &getPrevLookupResult() { + assert(PrevLookupResult); + return *PrevLookupResult; + } + const LookupResult &getPrevLookupResult() const { + assert(PrevLookupResult); + return *PrevLookupResult; + } + bool hasPrevLookupResult() const { return PrevLookupResult; } }; /// This little struct is used to capture information about Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -744,9 +744,10 @@ public: // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to // find a type name by attempting typo correction. - bool TryAnnotateTypeOrScopeToken(); + bool TryAnnotateTypeOrScopeToken(bool AllowImplicitTypename = false); bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, - bool IsNewScope); + bool IsNewScope, + bool AllowImplicitTypename); bool TryAnnotateCXXScopeToken(bool EnteringContext = false); private: @@ -1993,6 +1994,7 @@ DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration DSC_top_level, // top-level/namespace declaration context DSC_template_param, // template parameter context + DSC_template_arg, // template argument context DSC_template_type_arg, // template type argument context DSC_objc_method_result, // ObjC method result context, enables 'instancetype' DSC_condition // condition declaration context @@ -2004,6 +2006,7 @@ switch (DSC) { case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_template_param: + case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: case DeclSpecContext::DSC_objc_method_result: @@ -2025,6 +2028,7 @@ switch (DSC) { case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_template_param: + case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: case DeclSpecContext::DSC_condition: @@ -2040,6 +2044,27 @@ llvm_unreachable("Missing DeclSpecContext case"); } + // Is this a context in which an implicit 'typename' is allowed? + static bool isImplicitTypenameContext(DeclSpecContext DSC) { + switch (DSC) { + case DeclSpecContext::DSC_class: + case DeclSpecContext::DSC_top_level: + case DeclSpecContext::DSC_type_specifier: + case DeclSpecContext::DSC_template_type_arg: + case DeclSpecContext::DSC_trailing: + case DeclSpecContext::DSC_alias_declaration: + case DeclSpecContext::DSC_template_param: + return true; + + case DeclSpecContext::DSC_normal: + case DeclSpecContext::DSC_objc_method_result: + case DeclSpecContext::DSC_condition: + case DeclSpecContext::DSC_template_arg: + return false; + } + llvm_unreachable("Missing DeclSpecContext case"); + } + /// Information on a C++0x for-range-initializer found while parsing a /// declaration which turns out to be a for-range-declaration. struct ForRangeInit { @@ -2091,7 +2116,18 @@ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none, DeclSpecContext DSC = DeclSpecContext::DSC_normal, - LateParsedAttrList *LateAttrs = nullptr); + LateParsedAttrList *LateAttrs = nullptr) { + return ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, LateAttrs, + isImplicitTypenameContext(DSC)); + } + void ParseDeclarationSpecifiers( + DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, + DeclSpecContext DSC, + LateParsedAttrList *LateAttrs, + bool AllowImplicitTypename); + bool DiagnoseMissingSemiAfterTagDefinition( DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs = nullptr); @@ -2216,7 +2252,8 @@ /// might be a constructor-style initializer. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. - bool isCXXFunctionDeclarator(bool *IsAmbiguous = nullptr); + bool isCXXFunctionDeclarator(bool *IsAmbiguous = nullptr, + bool AllowImplicitTypename = false); struct ConditionDeclarationOrInitStatementState; enum class ConditionOrInitStatement { @@ -2266,7 +2303,8 @@ /// Doesn't consume tokens. TPResult isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False, - bool *HasMissingTypename = nullptr); + bool *HasMissingTypename = nullptr, + bool AllowImplicitTypename = false); /// Given that isCXXDeclarationSpecifier returns \c TPResult::True or /// \c TPResult::Ambiguous, determine whether the decl-specifier would be @@ -2295,7 +2333,8 @@ bool mayHaveDirectInit = false); TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = nullptr, - bool VersusTemplateArg = false); + bool VersusTemplateArg = false, + bool AllowImplicitTypename = false); TPResult TryParseFunctionDeclarator(); TPResult TryParseBracketDeclarator(); TPResult TryConsumeDeclarationSpecifier(); Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4430,6 +4430,12 @@ "%0 in %1">; def note_using_value_decl_missing_typename : Note< "add 'typename' to treat this using declaration as a type">; +def warn_cxx17_compat_implicit_typename : Warning<"use of implicit 'typename' is " + "incompatible with C++ standards before C++2a">, InGroup<CXX2aCompat>, + DefaultIgnore; +def ext_implicit_typename : ExtWarn<"missing 'typename' prior to dependent " + "type name %0%1; implicit 'typename' is a C++2a extension">, + InGroup<CXX2a>; def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits