r270615 - [ms] Allow more unqualified lookup of types in dependent base classes
Reid Kleckner via cfe-commits
cfe-commits at lists.llvm.org
Tue May 24 14:23:55 PDT 2016
Author: rnk
Date: Tue May 24 16:23:54 2016
New Revision: 270615
URL: http://llvm.org/viewvc/llvm-project?rev=270615&view=rev
Log:
[ms] Allow more unqualified lookup of types in dependent base classes
Summary:
In dependent contexts where we know a type name is required, such as a
new expression, we can recover by forming a DependentNameType.
This generalizes our existing compatibility hack for default arguments
for template type parameters.
Works towards parsing atlctrlw.h, which is PR26748.
Reviewers: avt77, rsmith
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D20500
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/SemaTemplate/ms-delayed-default-template-args.cpp
cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=270615&r1=270614&r2=270615&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue May 24 16:23:54 2016
@@ -1529,12 +1529,13 @@ public:
ParsedType &SuggestedType,
bool AllowClassTemplates = false);
- /// \brief For compatibility with MSVC, we delay parsing of some default
- /// template type arguments until instantiation time. Emits a warning and
- /// returns a synthesized DependentNameType that isn't really dependent on any
- /// other template arguments.
- ParsedType ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II,
- SourceLocation NameLoc);
+ /// Attempt to behave like MSVC in situations where lookup of an unqualified
+ /// type name has failed in a dependent context. In these situations, we
+ /// automatically form a DependentTypeName that will retry lookup in a related
+ /// scope during instantiation.
+ ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation NameLoc,
+ bool IsTemplateTypeArg);
/// \brief Describes the result of the name lookup and resolution performed
/// by \c ClassifyName().
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=270615&r1=270614&r2=270615&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue May 24 16:23:54 2016
@@ -2279,6 +2279,24 @@ bool Parser::ParseImplicitInt(DeclSpec &
return false;
}
+ if (getLangOpts().CPlusPlus && (!SS || SS->isEmpty()) &&
+ getLangOpts().MSVCCompat) {
+ // Lookup of an unqualified type name has failed in MSVC compatibility mode.
+ // Give Sema a chance to recover if we are in a template with dependent base
+ // classes.
+ if (ParsedType T = Actions.ActOnMSVCUnknownTypeName(
+ *Tok.getIdentifierInfo(), Tok.getLocation(),
+ DSC == DSC_template_type_arg)) {
+ const char *PrevSpec;
+ unsigned DiagID;
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T,
+ Actions.getASTContext().getPrintingPolicy());
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ return false;
+ }
+ }
+
// Otherwise, if we don't consume this token, we are going to emit an
// error anyway. Try to recover from various common problems. Check
// to see if this was a reference to a tag name without a tag specified.
@@ -2986,16 +3004,6 @@ void Parser::ParseDeclarationSpecifiers(
Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope());
- // MSVC: If we weren't able to parse a default template argument, and it's
- // just a simple identifier, create a DependentNameType. This will allow
- // us to defer the name lookup to template instantiation time, as long we
- // forge a NestedNameSpecifier for the current context.
- if (!TypeRep && DSContext == DSC_template_type_arg &&
- getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) {
- TypeRep = Actions.ActOnDelayedDefaultTemplateArg(
- *Tok.getIdentifierInfo(), Tok.getLocation());
- }
-
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=270615&r1=270614&r2=270615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue May 24 16:23:54 2016
@@ -473,17 +473,53 @@ synthesizeCurrentNestedNameSpecifier(AST
llvm_unreachable("something isn't in TU scope?");
}
-ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II,
- SourceLocation NameLoc) {
- // Accepting an undeclared identifier as a default argument for a template
- // type parameter is a Microsoft extension.
- Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II;
-
- // Build a fake DependentNameType that will perform lookup into CurContext at
- // instantiation time. The name specifier isn't dependent, so template
- // instantiation won't transform it. It will retry the lookup, however.
- NestedNameSpecifier *NNS =
- synthesizeCurrentNestedNameSpecifier(Context, CurContext);
+/// Find the parent class with dependent bases of the innermost enclosing method
+/// context. Do not look for enclosing CXXRecordDecls directly, or we will end
+/// up allowing unqualified dependent type names at class-level, which MSVC
+/// correctly rejects.
+static const CXXRecordDecl *
+findRecordWithDependentBasesOfEnclosingMethod(const DeclContext *DC) {
+ for (; DC && DC->isDependentContext(); DC = DC->getLookupParent()) {
+ DC = DC->getPrimaryContext();
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(DC))
+ if (MD->getParent()->hasAnyDependentBases())
+ return MD->getParent();
+ }
+ return nullptr;
+}
+
+ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation NameLoc,
+ bool IsTemplateTypeArg) {
+ assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode");
+
+ NestedNameSpecifier *NNS = nullptr;
+ if (IsTemplateTypeArg && getCurScope()->isTemplateParamScope()) {
+ // If we weren't able to parse a default template argument, delay lookup
+ // until instantiation time by making a non-dependent DependentTypeName. We
+ // pretend we saw a NestedNameSpecifier referring to the current scope, and
+ // lookup is retried.
+ // FIXME: This hurts our diagnostic quality, since we get errors like "no
+ // type named 'Foo' in 'current_namespace'" when the user didn't write any
+ // name specifiers.
+ NNS = synthesizeCurrentNestedNameSpecifier(Context, CurContext);
+ Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II;
+ } else if (const CXXRecordDecl *RD =
+ findRecordWithDependentBasesOfEnclosingMethod(CurContext)) {
+ // Build a DependentNameType that will perform lookup into RD at
+ // instantiation time.
+ NNS = NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(),
+ RD->getTypeForDecl());
+
+ // Diagnose that this identifier was undeclared, and retry the lookup during
+ // template instantiation.
+ Diag(NameLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << &II
+ << RD;
+ } else {
+ // This is not a situation that we should recover from.
+ return ParsedType();
+ }
+
QualType T = Context.getDependentNameType(ETK_None, NNS, &II);
// Build type location information. We synthesized the qualifier, so we have
Modified: cfe/trunk/test/SemaTemplate/ms-delayed-default-template-args.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-delayed-default-template-args.cpp?rev=270615&r1=270614&r2=270615&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-delayed-default-template-args.cpp (original)
+++ cfe/trunk/test/SemaTemplate/ms-delayed-default-template-args.cpp Tue May 24 16:23:54 2016
@@ -55,6 +55,15 @@ struct Foo {
typedef int Weber;
}
+// MSVC accepts this, but Clang doesn't.
+namespace test_scope_spec {
+template <typename T = ns::Bar> // expected-error {{use of undeclared identifier 'ns'}}
+struct Foo {
+ static_assert(sizeof(T) == 4, "Bar should have gotten int");
+};
+namespace ns { typedef int Bar; }
+}
+
#ifdef __clang__
// These are negative test cases that MSVC doesn't compile either. Try to use
// unique undeclared identifiers so typo correction doesn't find types declared
Modified: cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp?rev=270615&r1=270614&r2=270615&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp (original)
+++ cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp Tue May 24 16:23:54 2016
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s
template <class T>
@@ -573,3 +573,33 @@ void h();
template <typename T> decltype(h(T())) check2(); // expected-note{{candidate template ignored: substitution failure [with T = int]: no matching function for call to 'h'}}
decltype(check2<int>()) y; // expected-error{{no matching function for call to 'check2'}}
}
+
+// We also allow unqualified lookup into bases in contexts where the we know the
+// undeclared identifier *must* be a type, such as a new expression or catch
+// parameter type.
+template <typename T>
+struct UseUnqualifiedTypeNames : T {
+ void foo() {
+ void *P = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+ size_t x = __builtin_offsetof(TheType, f2); // expected-warning {{unqualified lookup}} expected-error {{no type}}
+ try {
+ } catch (TheType) { // expected-warning {{unqualified lookup}} expected-error {{no type}}
+ }
+ enum E : IntegerType { E0 = 42 }; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+ _Atomic(TheType) a; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+ }
+ void out_of_line();
+};
+template <typename T>
+void UseUnqualifiedTypeNames<T>::out_of_line() {
+ void *p = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+}
+struct Base {
+ typedef int IntegerType;
+ struct TheType {
+ int f1, f2;
+ };
+};
+template struct UseUnqualifiedTypeNames<Base>;
+struct BadBase { };
+template struct UseUnqualifiedTypeNames<BadBase>; // expected-note-re 2 {{in instantiation {{.*}} requested here}}
More information about the cfe-commits
mailing list