Scope *S,
const CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
+ TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
SourceLocation LParenLoc,
ExprTy **Args, unsigned NumArgs,
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS);
-
- if (Tok.isNot(tok::identifier)) {
+ TypeTy *TemplateTypeTy = 0;
+ if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ AnnotateTemplateIdTokenAsType(&SS);
+ assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
+ TemplateTypeTy = Tok.getAnnotationValue();
+ }
+ // FIXME. May need to check for TNK_Dependent_template as well.
+ }
+ if (!TemplateTypeTy && Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_member_or_base_name);
return true;
}
-
+
// Get the identifier. This may be a member name or a class name,
// but we'll let the semantic analysis determine which it is.
- IdentifierInfo *II = Tok.getIdentifierInfo();
+ IdentifierInfo *II = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : 0;
SourceLocation IdLoc = ConsumeToken();
// Parse the '('.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, SS, II, IdLoc,
+ return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, SS, II,
+ TemplateTypeTy, IdLoc,
LParenLoc, ArgExprs.take(),
ArgExprs.size(), CommaLocs.data(),
RParenLoc);
Scope *S,
const CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
+ TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
SourceLocation LParenLoc,
ExprTy **Args, unsigned NumArgs,
Scope *S,
const CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
+ TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
SourceLocation LParenLoc,
ExprTy **Args, unsigned NumArgs,
// composed of a single identifier refers to the class member. A
// mem-initializer-id for the hidden base class may be specified
// using a qualified name. ]
- if (!SS.getScopeRep()) {
+ if (!SS.getScopeRep() && !TemplateTypeTy) {
// Look for a member, first.
FieldDecl *Member = 0;
DeclContext::lookup_result Result
}
}
// It didn't name a member, so see if it names a class.
- TypeTy *BaseTy = getTypeName(*MemberOrBase, IdLoc, S, &SS);
+ TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
+ : getTypeName(*MemberOrBase, IdLoc, S, &SS);
if (!BaseTy)
return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
- if (!BaseType->isRecordType())
+ if (!BaseType->isRecordType() && !BaseType->isDependentType())
return Diag(IdLoc, diag::err_base_init_does_not_name_class)
<< BaseType << SourceRange(IdLoc, RParenLoc);
--- /dev/null
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class X> struct A {};
+
+template<class X> struct B : A<X> {
+ B() : A<X>() {}
+};
+B<int> x;
+
+template<class X> struct B1 : A<X> {
+ typedef A<X> Base;
+ B1() : Base() {}
+};
+B1<int> x1;
+
+
+template<typename T> struct Tmpl { };
+
+template<typename T> struct TmplB { };
+
+struct TmplC : Tmpl<int> {
+ TmplC() :
+ Tmpl<int>(),
+ TmplB<int>() { } // expected-error {{type 'TmplB<int>' is not a direct or virtual base of 'TmplC'}}
+};
+
+
+struct TmplD : Tmpl<char>, TmplB<char> {
+ TmplD():
+ Tmpl<int>(), // expected-error {{type 'Tmpl<int>' is not a direct or virtual base of 'TmplD'}}
+ TmplB<char>() {}
+};
+