summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--lib/Parse/ParseExprCXX.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--lib/Sema/SemaExprMember.cpp35
-rw-r--r--lib/Sema/SemaTemplate.cpp136
-rw-r--r--lib/Sema/TreeTransform.h31
-rw-r--r--test/CXX/drs/dr1xx.cpp3
-rw-r--r--test/CXX/drs/dr3xx.cpp3
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_in_class.cpp8
-rw-r--r--test/SemaCXX/invalid-template-specifier.cpp2
-rw-r--r--test/SemaObjCXX/parameterized_classes_subst.mm2
-rw-r--r--test/SemaTemplate/dependent-base-classes.cpp4
-rw-r--r--test/SemaTemplate/metafun-apply.cpp2
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp6
-rw-r--r--test/SemaTemplate/template-id-expr.cpp35
-rw-r--r--test/SemaTemplate/typo-dependent-name.cpp35
17 files changed, 211 insertions, 105 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 1c89412f7c..ad0235c560 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4505,6 +4505,8 @@ def note_using_value_decl_missing_typename : Note<
def err_template_kw_refers_to_non_template : Error<
"%0 following the 'template' keyword does not refer to a template">;
+def note_template_kw_refers_to_non_template : Note<
+ "declared as a non-template here">;
def err_template_kw_refers_to_class_template : Error<
"'%0%1' instantiated to a class template, not a function template">;
def note_referenced_class_template : Note<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 6f57944a6d..77427ee0e1 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -6090,9 +6090,10 @@ public:
bool hasAnyAcceptableTemplateNames(LookupResult &R,
bool AllowFunctionTemplates = true);
- void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
+ bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
- bool &MemberOfUnknownSpecialization);
+ bool &MemberOfUnknownSpecialization,
+ SourceLocation TemplateKWLoc = SourceLocation());
TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 1c859c19e2..ad91ff0021 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -515,7 +515,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
<< FixItHint::CreateInsertion(Tok.getLocation(), "template ");
if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
- getCurScope(), SS, SourceLocation(), TemplateName, ObjectType,
+ getCurScope(), SS, Tok.getLocation(), TemplateName, ObjectType,
EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
// Consume the identifier.
ConsumeToken();
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 1bec833d81..8d0de0b66c 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2087,8 +2087,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
bool MemberOfUnknownSpecialization;
- LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
- MemberOfUnknownSpecialization);
+ if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ MemberOfUnknownSpecialization, TemplateKWLoc))
+ return ExprError();
if (MemberOfUnknownSpecialization ||
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 2e099ad6c6..c91b15e29f 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -640,6 +640,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
const RecordType *RTy,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, bool HasTemplateArgs,
+ SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
RecordDecl *RDecl = RTy->getDecl();
@@ -649,13 +650,13 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
BaseRange))
return true;
- if (HasTemplateArgs) {
+ if (HasTemplateArgs || TemplateKWLoc.isValid()) {
// LookupTemplateName doesn't expect these both to exist simultaneously.
QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
bool MOUS;
- SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS);
- return false;
+ return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
+ TemplateKWLoc);
}
DeclContext *DC = RDecl;
@@ -733,7 +734,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
ExprResult &BaseExpr, bool &IsArrow,
SourceLocation OpLoc, CXXScopeSpec &SS,
- Decl *ObjCImpDecl, bool HasTemplateArgs);
+ Decl *ObjCImpDecl, bool HasTemplateArgs,
+ SourceLocation TemplateKWLoc);
ExprResult
Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
@@ -761,7 +763,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
if (LookupMemberExprInRecord(
*this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow,
- SS, TemplateKWLoc.isValid() || TemplateArgs != nullptr, TE))
+ SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
return ExprError();
if (TE)
return TE;
@@ -772,7 +774,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
ExprResult Result =
LookupMemberExpr(*this, R, BaseResult, IsArrow, OpLoc, SS,
ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr,
- TemplateKWLoc.isValid() || TemplateArgs != nullptr);
+ TemplateArgs != nullptr, TemplateKWLoc);
if (BaseResult.isInvalid())
return ExprError();
@@ -1226,7 +1228,8 @@ Sema::PerformMemberExprBaseConversion(Expr *Base, bool IsArrow) {
static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
ExprResult &BaseExpr, bool &IsArrow,
SourceLocation OpLoc, CXXScopeSpec &SS,
- Decl *ObjCImpDecl, bool HasTemplateArgs) {
+ Decl *ObjCImpDecl, bool HasTemplateArgs,
+ SourceLocation TemplateKWLoc) {
assert(BaseExpr.get() && "no base expression");
// Perform default conversions.
@@ -1276,8 +1279,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
// Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
TypoExpr *TE = nullptr;
- if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy,
- OpLoc, IsArrow, SS, HasTemplateArgs, TE))
+ if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS,
+ HasTemplateArgs, TemplateKWLoc, TE))
return ExprError();
// Returning valid-but-null is how we indicate to the caller that
@@ -1315,7 +1318,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
OpLoc, S.Context.getObjCClassType());
if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
goto fail;
}
@@ -1509,7 +1512,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
// use the 'id' redefinition in this case.
if (IsArrow && ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
return ExprError(S.Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
@@ -1522,7 +1525,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (!MD) {
if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
goto fail;
}
@@ -1564,7 +1567,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
return ExprError(S.Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
@@ -1609,7 +1612,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
BaseExpr = S.ImpCastExprToType(
BaseExpr.get(), S.Context.getObjCSelRedefinitionType(), CK_BitCast);
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
}
// Failure cases.
@@ -1632,7 +1635,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
// Recurse as an -> access.
IsArrow = true;
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
}
}
@@ -1646,7 +1649,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
return ExprError();
BaseExpr = S.DefaultFunctionArrayConversion(BaseExpr.get());
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
+ ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
}
S.Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index a4b9086aa4..b2ac7d98d5 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -189,8 +189,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
QualType ObjectType = ObjectTypePtr.get();
LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName);
- LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
- MemberOfUnknownSpecialization);
+ if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
+ MemberOfUnknownSpecialization))
+ return TNK_Non_template;
if (R.empty()) return TNK_Non_template;
if (R.isAmbiguous()) {
// Suppress diagnostics; we'll redo this lookup later.
@@ -252,8 +253,10 @@ bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
// syntactic form of a deduction guide is enough to identify it even
// if we can't look up the template name at all.
LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
- LookupTemplateName(R, S, SS, /*ObjectType*/QualType(),
- /*EnteringContext*/false, MemberOfUnknownSpecialization);
+ if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(),
+ /*EnteringContext*/ false,
+ MemberOfUnknownSpecialization))
+ return false;
if (R.empty()) return false;
if (R.isAmbiguous()) {
@@ -298,39 +301,40 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
return true;
}
-void Sema::LookupTemplateName(LookupResult &Found,
+bool Sema::LookupTemplateName(LookupResult &Found,
Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
bool EnteringContext,
- bool &MemberOfUnknownSpecialization) {
+ bool &MemberOfUnknownSpecialization,
+ SourceLocation TemplateKWLoc) {
// Determine where to perform name lookup
MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = nullptr;
- bool isDependent = false;
+ bool IsDependent = false;
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
- isDependent = ObjectType->isDependentType();
- assert((isDependent || !ObjectType->isIncompleteType() ||
+ IsDependent = !LookupCtx;
+ assert((IsDependent || !ObjectType->isIncompleteType() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
// Template names cannot appear inside an Objective-C class or object type.
if (ObjectType->isObjCObjectOrInterfaceType()) {
Found.clear();
- return;
+ return false;
}
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
LookupCtx = computeDeclContext(SS, EnteringContext);
- isDependent = isDependentScopeSpecifier(SS);
+ IsDependent = !LookupCtx;
// The declaration context must be complete.
if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
- return;
+ return true;
}
bool ObjectTypeSearchedInScope = false;
@@ -341,34 +345,43 @@ void Sema::LookupTemplateName(LookupResult &Found,
// expression or the declaration context associated with a prior
// nested-name-specifier.
LookupQualifiedName(Found, LookupCtx);
- if (!ObjectType.isNull() && Found.empty()) {
- // C++ [basic.lookup.classref]p1:
- // In a class member access expression (5.2.5), if the . or -> token is
- // immediately followed by an identifier followed by a <, the
- // identifier must be looked up to determine whether the < is the
- // beginning of a template argument list (14.2) or a less-than operator.
- // The identifier is first looked up in the class of the object
- // expression. If the identifier is not found, it is then looked up in
- // the context of the entire postfix-expression and shall name a class
- // or function template.
- if (S) LookupName(Found, S);
- ObjectTypeSearchedInScope = true;
+
+ // FIXME: The C++ standard does not clearly specify what happens in the
+ // case where the object type is dependent, and implementations vary. In
+ // Clang, we treat a name after a . or -> as a template-name if lookup
+ // finds a non-dependent member or member of the current instantiation that
+ // is a type template, or finds no such members and lookup in the context
+ // of the postfix-expression finds a type template. In the latter case, the
+ // name is nonetheless dependent, and we may resolve it to a member of an
+ // unknown specialization when we come to instantiate the template.
+ IsDependent |= Found.wasNotFoundInCurrentInstantiation();
+ }
+
+ if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) {
+ // C++ [basic.lookup.classref]p1:
+ // In a class member access expression (5.2.5), if the . or -> token is
+ // immediately followed by an identifier followed by a <, the
+ // identifier must be looked up to determine whether the < is the
+ // beginning of a template argument list (14.2) or a less-than operator.
+ // The identifier is first looked up in the class of the object
+ // expression. If the identifier is not found, it is then looked up in
+ // the context of the entire postfix-expression and shall name a class
+ // template.
+ if (S)
+ LookupName(Found, S);
+
+ if (!ObjectType.isNull()) {
+ // FIXME: We should filter out all non-type templates here, particularly
+ // variable templates and concepts. But the exclusion of alias templates
+ // and template template parameters is a wording defect.
AllowFunctionTemplatesInLookup = false;
+ ObjectTypeSearchedInScope = true;
}
- } else if (isDependent && (!S || ObjectType.isNull())) {
- // We cannot look into a dependent object type or nested nme
- // specifier.
- MemberOfUnknownSpecialization = true;
- return;
- } else {
- // Perform unqualified name lookup in the current scope.
- LookupName(Found, S);
- if (!ObjectType.isNull())
- AllowFunctionTemplatesInLookup = false;
+ IsDependent |= Found.wasNotFoundInCurrentInstantiation();
}
- if (Found.empty() && !isDependent) {
+ if (Found.empty() && !IsDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
@@ -402,11 +415,27 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
+ NamedDecl *ExampleLookupResult =
+ Found.empty() ? nullptr : Found.getRepresentativeDecl();
FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
if (Found.empty()) {
- if (isDependent)
+ if (IsDependent) {
MemberOfUnknownSpecialization = true;
- return;
+ return false;
+ }
+
+ // If a 'template' keyword was used, a lookup that finds only non-template
+ // names is an error.
+ if (ExampleLookupResult && TemplateKWLoc.isValid()) {
+ Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template)
+ << Found.getLookupName() << SS.getRange();
+ Diag(ExampleLookupResult->getLocation(),
+ diag::note_template_kw_refers_to_non_template)
+ << Found.getLookupName();
+ return true;
+ }
+
+ return false;
}
if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope &&
@@ -453,6 +482,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
}
+
+ return false;
}
void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
@@ -4069,15 +4100,17 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
bool MemberOfUnknownSpecialization;
LookupResult R(*this, NameInfo, LookupOrdinaryName);
- LookupTemplateName(R, (Scope*)nullptr, SS, QualType(), /*Entering*/ false,
- MemberOfUnknownSpecialization);
+ if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
+ /*Entering*/false, MemberOfUnknownSpecialization,
+ TemplateKWLoc))
+ return ExprError();
if (R.isAmbiguous())
return ExprError();
if (R.empty()) {
- Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_non_template)
- << NameInfo.getName() << SS.getRange();
+ Diag(NameInfo.getLoc(), diag::err_no_member)
+ << NameInfo.getName() << DC << SS.getRange();
return ExprError();
}
@@ -4140,17 +4173,20 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
ObjectType, EnteringContext, Result,
MemberOfUnknownSpecialization);
- if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
- isa<CXXRecordDecl>(LookupCtx) &&
- (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() ||
- cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases())) {
+ if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) {
// This is a dependent template. Handle it below.
} else if (TNK == TNK_Non_template) {
- Diag(Name.getLocStart(),
- diag::err_template_kw_refers_to_non_template)
- << GetNameFromUnqualifiedId(Name).getName()
- << Name.getSourceRange()
- << TemplateKWLoc;
+ // Do the lookup again to determine if this is a "nothing found" case or
+ // a "not a template" case. FIXME: Refactor isTemplateName so we don't
+ // need to do this.
+ DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
+ LookupResult R(*this, DNI.getName(), Name.getLocStart(),
+ LookupOrdinaryName);
+ bool MOUS;
+ if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
+ MOUS, TemplateKWLoc))
+ Diag(Name.getLocStart(), diag::err_no_member)
+ << DNI.getName() << LookupCtx << SS.getRange();
return TNK_Non_template;
} else {
// We found something; return it.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 938a966dbc..cdf7dc419f 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -957,6 +957,7 @@ public:
QualType RebuildDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const IdentifierInfo *Name,
SourceLocation NameLoc,
TemplateArgumentListInfo &Args,
@@ -965,9 +966,9 @@ public:
// TODO: avoid TemplateName abstraction
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- TemplateName InstName
- = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(),
- nullptr, AllowInjectedClassName);
+ TemplateName InstName = getDerived().RebuildTemplateName(
+ SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr,
+ AllowInjectedClassName);
if (InstName.isNull())
return QualType();
@@ -1146,9 +1147,9 @@ public:
/// template name. Subclasses may override this routine to provide different
/// behavior.
TemplateName RebuildTemplateName(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
- SourceLocation NameLoc,
- QualType ObjectType,
+ SourceLocation NameLoc, QualType ObjectType,
NamedDecl *FirstQualifierInScope,
bool AllowInjectedClassName);
@@ -1160,9 +1161,9 @@ public:
/// template name. Subclasses may override this routine to provide different
/// behavior.
TemplateName RebuildTemplateName(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
OverloadedOperatorKind Operator,
- SourceLocation NameLoc,
- QualType ObjectType,
+ SourceLocation NameLoc, QualType ObjectType,
bool AllowInjectedClassName);
/// Build a new template name given a template template parameter pack
@@ -3752,8 +3753,12 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
ObjectType.isNull())
return Name;
+ // FIXME: Preserve the location of the "template" keyword.
+ SourceLocation TemplateKWLoc = NameLoc;
+
if (DTN->isIdentifier()) {
return getDerived().RebuildTemplateName(SS,
+ TemplateKWLoc,
*DTN->getIdentifier(),
NameLoc,
ObjectType,
@@ -3761,7 +3766,8 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
AllowInjectedClassName);
}
- return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc,
+ return getDerived().RebuildTemplateName(SS, TemplateKWLoc,
+ DTN->getOperator(), NameLoc,
ObjectType, AllowInjectedClassName);
}
@@ -4340,6 +4346,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
TemplateName Template
= getDerived().RebuildTemplateName(SS,
+ SpecTL.getTemplateKeywordLoc(),
*SpecTL.getTypePtr()->getIdentifier(),
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup,
@@ -6138,8 +6145,8 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
return QualType();
QualType Result = getDerived().RebuildDependentTemplateSpecializationType(
- T->getKeyword(), QualifierLoc, T->getIdentifier(),
- TL.getTemplateNameLoc(), NewTemplateArgs,
+ T->getKeyword(), QualifierLoc, TL.getTemplateKeywordLoc(),
+ T->getIdentifier(), TL.getTemplateNameLoc(), NewTemplateArgs,
/*AllowInjectedClassName*/ false);
if (Result.isNull())
return QualType();
@@ -12510,6 +12517,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
QualType ObjectType,
@@ -12518,7 +12526,6 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
- SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
getSema().ActOnDependentTemplateName(/*Scope=*/nullptr,
SS, TemplateKWLoc, TemplateName,
ParsedType::make(ObjectType),
@@ -12530,6 +12537,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
OverloadedOperatorKind Operator,
SourceLocation NameLoc,
QualType ObjectType,
@@ -12538,7 +12546,6 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
// FIXME: Bogus location information.
SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations);
- SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
Sema::TemplateTy Template;
getSema().ActOnDependentTemplateName(/*Scope=*/nullptr,
SS, TemplateKWLoc, Name,
diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp
index 391b152737..1507c67b9d 100644
--- a/test/CXX/drs/dr1xx.cpp
+++ b/test/CXX/drs/dr1xx.cpp
@@ -71,7 +71,8 @@ namespace dr109 { // dr109: yes
using T::template f<int>; // expected-error {{'template' keyword not permitted here}} expected-error {{using declaration cannot refer to a template specialization}}
// FIXME: We shouldn't suggest using the 'template' keyword in a location where it's not valid.
using T::f<int>; // expected-error {{use 'template' keyword}} expected-error {{using declaration cannot refer to a template specialization}}
- void g() { this->f<int>(123); } // expected-error {{use 'template'}}
+ // FIXME: The first 'using' above introduces 'f' as a non-template member of 'B', leading to bad recovery:
+ void g() { this->f<int>(123); } // expected-error {{expected '('}}
};
}
diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp
index 9a5e51a78c..15261007dd 100644
--- a/test/CXX/drs/dr3xx.cpp
+++ b/test/CXX/drs/dr3xx.cpp
@@ -123,8 +123,7 @@ namespace dr305 { // dr305: no
template<typename T> using T2 = T;
};
void k(Z *z) {
- // FIXME: This diagnostic is terrible.
- z->~T1<int>(); // expected-error {{'T1' following the 'template' keyword does not refer to a template}} expected-error +{{}}
+ z->~T1<int>(); // expected-error {{no member named 'T1' in 'dr305::Z'}} expected-error +{{}}
z->~T2<int>(); // expected-error {{no member named '~int'}}
z->~T2<Z>();
}
diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
index 4afc80f962..b09305d7a0 100644
--- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -296,17 +296,17 @@ namespace in_class_template {
};
template<typename T> void f() {
- typename T::template A<int> a; // expected-error {{template name refers to non-type template 'S::A'}}
+ typename T::template A<int> a; // expected-error {{template name refers to non-type template 'S::template A'}}
}
template<typename T> void g() {
- T::template A<int>::B = 0; // expected-error {{template name refers to non-type template 'S::A'}}
+ T::template A<int>::B = 0; // expected-error {{template name refers to non-type template 'S::template A'}}
}
template<typename T> void h() {
- class T::template A<int> c; // expected-error {{template name refers to non-type template 'S::A'}}
+ class T::template A<int> c; // expected-error {{template name refers to non-type template 'S::template A'}}
}
template<typename T>
- struct X : T::template A<int> {}; // expected-error {{template name refers to non-type template 'S::A'}}
+ struct X : T::template A<int> {}; // expected-error {{template name refers to non-type template 'S::template A'}}
template void f<S>(); // expected-note {{in instantiation of}}
template void g<S>(); // expected-note {{in instantiation of}}
diff --git a/test/SemaCXX/invalid-template-specifier.cpp b/test/SemaCXX/invalid-template-specifier.cpp
index bcd6da7f32..140ad00c9e 100644
--- a/test/SemaCXX/invalid-template-specifier.cpp
+++ b/test/SemaCXX/invalid-template-specifier.cpp
@@ -7,6 +7,6 @@ const template basic_istream<char>; // expected-error {{expected unqualified-id}
namespace S {}
template <class X> class Y {
- void x() { S::template y<char>(1); } // expected-error {{does not refer to a template}} \
+ void x() { S::template y<char>(1); } // expected-error {{no member named 'y' in namespace 'S'}} \
// expected-error {{unqualified-id}}
};
diff --git a/test/SemaObjCXX/parameterized_classes_subst.mm b/test/SemaObjCXX/parameterized_classes_subst.mm
index f342ac0224..88d001274b 100644
--- a/test/SemaObjCXX/parameterized_classes_subst.mm
+++ b/test/SemaObjCXX/parameterized_classes_subst.mm
@@ -419,7 +419,7 @@ struct DependentTemplate {
};
struct NSMutableDictionaryBuilder {
- typedef NSMutableDictionary apply;
+ typedef NSMutableDictionary apply; // expected-note 2{{declared as a non-template here}}
};
typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}}
diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp
index 1853511bfc..6d342f984d 100644
--- a/test/SemaTemplate/dependent-base-classes.cpp
+++ b/test/SemaTemplate/dependent-base-classes.cpp
@@ -55,7 +55,7 @@ namespace PR6031 {
struct NoDepBase {
int foo() {
class NoDepBase::Nested nested; // expected-error{{no class named 'Nested' in 'NoDepBase<T>'}}
- typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \
+ typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{no member named 'MemberTemplate' in 'NoDepBase<T>'}} \
// FIXME: expected-error{{unqualified-id}}
return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}}
}
@@ -103,7 +103,7 @@ namespace PR6081 {
template< class X >
void f0(const X & k)
{
- this->template f1<int>()(k); // expected-error{{'f1' following the 'template' keyword does not refer to a template}} \
+ this->template f1<int>()(k); // expected-error{{no member named 'f1' in 'C<T>'}} \
// FIXME: expected-error{{unqualified-id}} \
// expected-error{{function-style cast or type construction}} \
// expected-error{{expected expression}}
diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp
index 3a7408e280..55f6194a51 100644
--- a/test/SemaTemplate/metafun-apply.cpp
+++ b/test/SemaTemplate/metafun-apply.cpp
@@ -15,7 +15,7 @@ struct add_reference {
};
struct bogus {
- struct apply {
+ struct apply { // expected-note{{declared as a non-template here}}
typedef int type;
};
};
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
index 78d09d13de..e9d0eb2020 100644
--- a/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -49,7 +49,7 @@ namespace N {
struct X;
};
- struct B;
+ struct B; // expected-note{{declared as a non-template here}}
}
struct ::N::A<int>::X {
@@ -131,7 +131,7 @@ namespace PR9226 {
template<typename T, typename U>
struct Y {
- typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::f'}}
+ typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::template f'}}
};
Y<X, int> yxi; // expected-note{{in instantiation of template class 'PR9226::Y<PR9226::X, int>' requested here}}
@@ -144,7 +144,7 @@ namespace PR9449 {
template <typename T>
void f() {
int s<T>::template n<T>::* f; // expected-error{{implicit instantiation of undefined template 'PR9449::s<int>'}} \
- // expected-error{{following the 'template' keyword}}
+ // expected-error{{no member named 'n'}}
}
template void f<int>(); // expected-note{{in instantiation of}}
diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp
index e9f63fa754..0555d8b945 100644
--- a/test/SemaTemplate/template-id-expr.cpp
+++ b/test/SemaTemplate/template-id-expr.cpp
@@ -56,7 +56,7 @@ struct Y0 {
template<typename U>
static void f2(U);
- void f3(int);
+ void f3(int); // expected-note 2{{declared as a non-template here}}
static int f4(int);
template<typename U>
@@ -100,7 +100,7 @@ struct Y1 {
template<typename U>
static void f2(U);
- void f3(int);
+ void f3(int); // expected-note 4{{declared as a non-template here}}
static int f4(int);
template<typename U>
@@ -131,10 +131,39 @@ struct Y1 {
void use_Y1(Y1<int> y1) { y1.f<int>(); } // expected-note {{in instantiation of}}
+template<typename T>
+struct Y2 : Y1<T> {
+ typedef ::Y1<T> Y1;
+
+ template<typename U>
+ void f(Y1 *p) {
+ Y1::template f1<U>(0);
+ Y1::template f1(0);
+ p->template f1(0);
+
+ Y1::template f2<U>(0);
+ Y1::template f2(0);
+
+ Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
+ Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
+
+ int x;
+ x = Y1::f4(0);
+ x = Y1::f4<int>(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}}
+ x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+
+ x = p->f4(0);
+ x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}}
+ x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+ }
+};
+
+void use_Y2(Y2<int> y2) { y2.f<int>(0); } // expected-note {{in instantiation of}}
+
struct A {
template<int I>
struct B {
- static void b1();
+ static void b1(); // expected-note {{declared as a non-template here}}
};
};
diff --git a/test/SemaTemplate/typo-dependent-name.cpp b/test/SemaTemplate/typo-dependent-name.cpp
index 78cedd0c98..0231740f6c 100644
--- a/test/SemaTemplate/typo-dependent-name.cpp
+++ b/test/SemaTemplate/typo-dependent-name.cpp
@@ -1,18 +1,45 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+
+using nullptr_t = decltype(nullptr);
template<typename T>
struct Base {
T inner;
};
+int z;
+
template<typename T>
-struct X {
- template<typename U>
+struct X : Base<T> {
+ static int z;
+
+ template<int U>
struct Inner {
};
bool f(T other) {
- return this->inner < other;
+ // A pair of comparisons; 'inner' is a dependent name so can't be assumed
+ // to be a template.
+ return this->inner < other > ::z;
}
};
+
+void use_x(X<int> x) { x.f(0); }
+
+template<typename T>
+struct Y {
+ static int z;
+
+ template<int U>
+ struct Inner : Y { // expected-note {{declared here}}
+ };
+
+ bool f(T other) {
+ // We can determine that 'inner' does not exist at parse time, so can
+ // perform typo correction in this case.
+ return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}}
+ }
+};
+
+struct Q { constexpr operator int() { return 0; } };
+void use_y(Y<Q> x) { x.f(Q()); }