Rakete1111 updated this revision to Diff 190012.
Rakete1111 added a comment.
Herald added a subscriber: jdoerfert.
Herald added a project: clang.
Fix a bug where `T::value` inside a functional cast in a template argument
would be interpreted as a function type.
Also added the missing test file that got lost in a previous revision for some
reason. :)
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D53847/new/
https://reviews.llvm.org/D53847
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/DeclSpec.h
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Parse/ParseTemplate.cpp
clang/lib/Parse/ParseTentative.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/DeclSpec.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/test/CXX/drs/dr1xx.cpp
clang/test/CXX/drs/dr2xx.cpp
clang/test/CXX/drs/dr4xx.cpp
clang/test/CXX/drs/dr5xx.cpp
clang/test/CXX/temp/temp.res/p5.cpp
clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
clang/test/FixIt/fixit.cpp
clang/test/Parser/cxx-member-initializers.cpp
clang/test/Parser/editor-placeholder-recovery.cpp
clang/test/SemaCXX/MicrosoftCompatibility.cpp
clang/test/SemaCXX/MicrosoftExtensions.cpp
clang/test/SemaCXX/MicrosoftSuper.cpp
clang/test/SemaCXX/unknown-type-name.cpp
Index: clang/test/SemaCXX/unknown-type-name.cpp
===================================================================
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/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: clang/test/SemaCXX/MicrosoftSuper.cpp
===================================================================
--- clang/test/SemaCXX/MicrosoftSuper.cpp
+++ clang/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: clang/test/SemaCXX/MicrosoftExtensions.cpp
===================================================================
--- clang/test/SemaCXX/MicrosoftExtensions.cpp
+++ clang/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: clang/test/SemaCXX/MicrosoftCompatibility.cpp
===================================================================
--- clang/test/SemaCXX/MicrosoftCompatibility.cpp
+++ clang/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: clang/test/Parser/editor-placeholder-recovery.cpp
===================================================================
--- clang/test/Parser/editor-placeholder-recovery.cpp
+++ clang/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: clang/test/Parser/cxx-member-initializers.cpp
===================================================================
--- clang/test/Parser/cxx-member-initializers.cpp
+++ clang/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: clang/test/FixIt/fixit.cpp
===================================================================
--- clang/test/FixIt/fixit.cpp
+++ clang/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: clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
===================================================================
--- clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
+++ clang/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: clang/test/CXX/temp/temp.res/p5.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/temp/temp.res/p5.cpp
@@ -0,0 +1,159 @@
+// RUN: %clang_cc1 -std=c++2a -pedantic -verify %s
+
+struct X {
+ using type = int;
+ static constexpr int value = 1;
+ class tclass {};
+};
+
+// [temp.res]p5
+// A qualified-id is assumed to name a type if
+
+template <typename T>
+void f() {
+ // it is a qualified name in a type-id-only context (see below), or
+ // [its smallest enclosing [/new/defining/]-type-id is]:
+ // - a new-type-id
+ auto *Ptr = new T::type();
+ // - a defining-type-id
+ class T::tclass Empty1;
+ T::tclass Empty2; // expected-error{{missing 'typename'}}
+ // - a trailing-return-type
+ auto f()->T::type;
+ // - default argument of a type-parameter of a template [see below]
+
+ // - type-id of a
+ // static_cast,
+ auto StaticCast = static_cast<T::type>(1.2);
+ // const_cast,
+ const auto *ConstCast = const_cast<const T::type *>(Ptr);
+ // reinterpret_cast,
+ int ReinterpretCast = reinterpret_cast<T::type>(4);
+ // dynamic_cast
+ struct B {
+ virtual ~B() = default;
+ };
+ struct D : T::tclass {};
+ auto *Base = dynamic_cast<T::tclass *>(new B);
+
+ T::type Invalid; // expected-error{{missing 'typename'}}
+}
+
+template void f<X>();
+
+// As default argument.
+template <typename T, typename = T::type>
+struct DefaultArg {};
+
+template struct DefaultArg<X>;
+
+// it is a decl-specifier of the decl-specifier-seq of a
+// - simple-declaration or a function-definition in namespace scope
+template <typename T>
+T::type VarTemp = 1;
+
+template int VarTemp<X>;
+
+template <typename T>
+T::type FuncDef() { return 1; }
+
+template int FuncDef<X>();
+
+template <typename T>
+T::type funcDecl();
+
+template <typename T>
+void FuncParam(T::type); // ok, but variable template
+// expected-error@-1{{variable has incomplete type 'void'}}
+
+template <typename T>
+void FuncParam2(const T::type, int); // expected-error{{missing 'typename'}}
+
+template <typename T>
+struct MemberDecl {
+ // member-declaration,
+ T::type Member;
+
+ // parameter-declaration in a member-declaration, unless that
+ // parameter-declaration appears in a default argument
+ void NoDefault(T::type);
+ void Default(int A = T::value);
+};
+
+template struct MemberDecl<X>;
+
+// parameter-declaration in a declarator of a function or function template
+// declaration where the declarator-id is qualified, unless that
+// parameter-declaration appears in a default argument,
+struct QualifiedFunc {
+ template <typename T>
+ void foo(typename T::type);
+ template <typename T>
+ void bar(T::type);
+};
+
+template <typename T>
+void QualifiedFunc::foo(T::type) {}
+template <typename T>
+void QualifiedFunc::bar(typename T::type) {}
+
+template <typename T>
+void g() {
+ // parameter-declaration in a lambda-declarator, unless that
+ // parameter-declaration appears in a default argument, or
+ auto Lambda1 = [](T::type) {};
+ auto Lambda2 = [](int A = T::value) {};
+}
+
+template void g<X>();
+
+// parameter-declaration of a (non-type) template-parameter.
+template <typename T, T::type>
+void NonTypeArg() {}
+
+template void NonTypeArg<X, 0>();
+
+template <typename T>
+void f(T::type) {} // expected-error {{missing 'typename'}}
+
+namespace N {
+ template <typename T>
+ int f(typename T::type);
+ template <typename T>
+ extern int Var;
+}
+
+template <typename T>
+int N::f(T::type); // ok, function
+template <typename T>
+int N::Var(T::value); // ok, variable
+
+int h() {
+ return N::f<X>(10) + N::Var<X>;
+}
+
+namespace NN {
+ inline namespace A { template <typename T> int f(typename T::type); } // expected-note{{previous definition is here}}
+ inline namespace B { template <typename T> int f(T::type); }
+}
+
+template <typename T>
+int NN::f(T::type); // expected-error{{redefinition of 'f' as different kind of symbol}}
+
+template <auto V>
+struct videntity {
+ static constexpr auto value = V;
+};
+
+template <typename T,
+ bool = T::value,
+ bool = bool(T::value),
+ bool = videntity<bool(T::value)>::value>
+void f(int = T::value) {}
+
+template <typename> int test() = delete;
+template <auto> int test();
+
+template <typename T>
+int Test = test<int(T::value)>();
+template int Test<X>;
Index: clang/test/CXX/drs/dr5xx.cpp
===================================================================
--- clang/test/CXX/drs/dr5xx.cpp
+++ clang/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: clang/test/CXX/drs/dr4xx.cpp
===================================================================
--- clang/test/CXX/drs/dr4xx.cpp
+++ clang/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: clang/test/CXX/drs/dr2xx.cpp
===================================================================
--- clang/test/CXX/drs/dr2xx.cpp
+++ clang/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: clang/test/CXX/drs/dr1xx.cpp
===================================================================
--- clang/test/CXX/drs/dr1xx.cpp
+++ clang/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: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -9483,10 +9483,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;
@@ -9498,8 +9499,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: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -280,6 +280,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 &&
@@ -306,17 +307,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);
}
@@ -5438,7 +5454,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: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -2191,3 +2191,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: clang/lib/Sema/DeclSpec.cpp
===================================================================
--- clang/lib/Sema/DeclSpec.cpp
+++ clang/lib/Sema/DeclSpec.cpp
@@ -18,6 +18,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: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/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: clang/lib/Parse/ParseTentative.cpp
===================================================================
--- clang/lib/Parse/ParseTentative.cpp
+++ clang/lib/Parse/ParseTentative.cpp
@@ -1275,7 +1275,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
@@ -1305,7 +1308,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;
@@ -1326,7 +1329,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
@@ -1342,7 +1345,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);
@@ -1357,7 +1360,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);
@@ -1469,7 +1472,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
@@ -1778,7 +1781,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
@@ -1793,7 +1797,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;
@@ -1839,7 +1845,8 @@
///
Parser::TPResult
Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
- bool VersusTemplateArgument) {
+ bool VersusTemplateArgument,
+ bool AllowImplicitTypename) {
if (Tok.is(tok::r_paren))
return TPResult::Ambiguous;
@@ -1872,8 +1879,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: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -16,6 +16,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: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1343,7 +1343,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: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -1199,7 +1199,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: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -2649,6 +2649,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;
@@ -2712,22 +2715,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.
@@ -2944,7 +2971,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
@@ -3132,12 +3160,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
@@ -4827,7 +4856,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(!getCurScope()->isTemplateParamScope()))
return true;
if (Tok.is(tok::identifier))
return false;
@@ -5850,10 +5879,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;
@@ -6404,6 +6440,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.
@@ -6429,8 +6474,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: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1781,6 +1781,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);
@@ -2122,6 +2123,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);
@@ -6618,10 +6623,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: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -39,6 +39,7 @@
class CXXRecordDecl;
class TypeLoc;
class LangOptions;
+ class LookupResult;
class IdentifierInfo;
class NamespaceAliasDecl;
class NamespaceDecl;
@@ -1834,6 +1835,9 @@
/// this declarator as a parameter pack.
SourceLocation EllipsisLoc;
+ /// Lookup result of declarator, if any.
+ LookupResult *PrevLookupResult;
+
friend struct DeclaratorChunk;
public:
@@ -1843,7 +1847,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();
@@ -2482,6 +2487,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: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -771,9 +771,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:
@@ -2019,6 +2020,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
@@ -2030,6 +2032,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:
@@ -2051,6 +2054,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:
@@ -2066,6 +2070,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 {
@@ -2117,7 +2142,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);
@@ -2242,7 +2278,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 {
@@ -2292,7 +2329,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
@@ -2321,7 +2359,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: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4459,6 +4459,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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits