summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-06-06 22:36:36 +0000
committerReid Kleckner <reid@kleckner.net>2014-06-06 22:36:36 +0000
commitdf6e4a06e42b8282220a73e6299b30ff2ec329ed (patch)
tree1384aa1336da74d0c26d9a12c19d3f4da9acf480 /clang/lib
parent57e06dfb4123b2dc2b3483931f8319cc35bb44b3 (diff)
downloadbcm5719-llvm-df6e4a06e42b8282220a73e6299b30ff2ec329ed.tar.gz
bcm5719-llvm-df6e4a06e42b8282220a73e6299b30ff2ec329ed.zip
Delay lookup of simple default template arguments under -fms-compatibility
MSVC delays parsing of default arguments until instantiation. If the default argument is never used, it is never parsed. We don't model this. Instead, if lookup of a type name fails in a template argument context, we form a DependentNameType, which will be looked up at instantiation time. This fixes errors about 'CControlWinTraits' in atlwin.h. Reviewers: rsmith Differential Revision: http://reviews.llvm.org/D3995 llvm-svn: 210382
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp2
-rw-r--r--clang/lib/Parse/ParseDecl.cpp12
-rw-r--r--clang/lib/Sema/SemaDecl.cpp44
3 files changed, 56 insertions, 2 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 3f48e798687..4dff88bbebe 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3318,8 +3318,6 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon) const {
- assert(NNS->isDependent() && "nested-name-specifier must be dependent");
-
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
ElaboratedTypeKeyword CanonKeyword = Keyword;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 65ec44c5775..92a13659ea3 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2227,6 +2227,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_class;
if (Context == Declarator::FileContext)
return DSC_top_level;
+ if (Context == Declarator::TemplateTypeArgContext)
+ return DSC_template_type_arg;
if (Context == Declarator::TrailingReturnContext)
return DSC_trailing;
if (Context == Declarator::AliasDeclContext ||
@@ -2753,6 +2755,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index ed7431ae3e4..ec0c27b2d2e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -343,6 +343,50 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
return ParsedType::make(T);
}
+// Builds a fake NNS for the given decl context.
+static NestedNameSpecifier *
+synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) {
+ for (;; DC = DC->getLookupParent()) {
+ DC = DC->getPrimaryContext();
+ auto *ND = dyn_cast<NamespaceDecl>(DC);
+ if (ND && !ND->isInline() && !ND->isAnonymousNamespace())
+ return NestedNameSpecifier::Create(Context, nullptr, ND);
+ else if (auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(),
+ RD->getTypeForDecl());
+ else if (isa<TranslationUnitDecl>(DC))
+ return NestedNameSpecifier::GlobalSpecifier(Context);
+ }
+ 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);
+ QualType T = Context.getDependentNameType(ETK_None, NNS, &II);
+
+ // Build type location information. We synthesized the qualifier, so we have
+ // to build a fake NestedNameSpecifierLoc.
+ NestedNameSpecifierLocBuilder NNSLocBuilder;
+ NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc));
+ NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context);
+
+ TypeLocBuilder Builder;
+ DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T);
+ DepTL.setNameLoc(NameLoc);
+ DepTL.setElaboratedKeywordLoc(SourceLocation());
+ DepTL.setQualifierLoc(QualifierLoc);
+ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
/// isTagName() - This method is called *for error recovery purposes only*
/// to determine if the specified name is a valid tag name ("struct foo"). If
/// so, this returns the TST for the tag corresponding to it (TST_enum,
OpenPOWER on IntegriCloud