Skip to content

Commit

Permalink
Fix crash if base specifier parsing hits an invalid type annotation.
Browse files Browse the repository at this point in the history
Also change type annotation representation from ParsedType to TypeResult
to make it clearer to consumers that they can represent invalid types.
  • Loading branch information
zygoloid committed Mar 31, 2020
1 parent 5074776 commit 3308732
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 44 deletions.
10 changes: 7 additions & 3 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -763,13 +763,17 @@ class Parser : public CodeCompletionHandler {
}

/// getTypeAnnotation - Read a parsed type out of an annotation token.
static ParsedType getTypeAnnotation(const Token &Tok) {
static TypeResult getTypeAnnotation(const Token &Tok) {
if (!Tok.getAnnotationValue())
return TypeError();
return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
}

private:
static void setTypeAnnotation(Token &Tok, ParsedType T) {
Tok.setAnnotationValue(T.getAsOpaquePtr());
static void setTypeAnnotation(Token &Tok, TypeResult T) {
assert((T.isInvalid() || T.get()) &&
"produced a valid-but-null type annotation?");
Tok.setAnnotationValue(T.isInvalid() ? nullptr : T.get().getAsOpaquePtr());
}

static NamedDecl *getNonTypeAnnotation(const Token &Tok) {
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,13 @@ class DeclSpec {
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, ParsedType Rep,
const PrintingPolicy &Policy);
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, TypeResult Rep,
const PrintingPolicy &Policy) {
if (Rep.isInvalid())
return SetTypeSpecError();
return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Rep.get(), Policy);
}
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, Decl *Rep, bool Owned,
const PrintingPolicy &Policy);
Expand Down
26 changes: 9 additions & 17 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3217,16 +3217,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.is(tok::annot_typename)) {
DS.getTypeSpecScope() = SS;
ConsumeAnnotationToken(); // The C++ scope.
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, T, Policy);
if (isInvalid)
break;
}
else
DS.SetTypeSpecError();
TypeResult T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, T, Policy);
if (isInvalid)
break;
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeAnnotationToken(); // The typename
}
Expand Down Expand Up @@ -3294,13 +3290,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
goto DoneWithDeclSpec;

if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, T, Policy);
} else
DS.SetTypeSpecError();

TypeResult T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, T, Policy);
if (isInvalid)
break;

Expand Down
28 changes: 16 additions & 12 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1151,13 +1151,10 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);

assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
ParsedType Type = getTypeAnnotation(Tok);
TypeResult Type = getTypeAnnotation(Tok);
EndLocation = Tok.getAnnotationEndLoc();
ConsumeAnnotationToken();

if (Type)
return Type;
return true;
return Type;
}

// Fall through to produce an error below.
Expand Down Expand Up @@ -1204,7 +1201,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// Retrieve the type from the annotation token, consume that token, and
// return.
EndLocation = Tok.getAnnotationEndLoc();
ParsedType Type = getTypeAnnotation(Tok);
TypeResult Type = getTypeAnnotation(Tok);
ConsumeAnnotationToken();
return Type;
}
Expand Down Expand Up @@ -3510,7 +3507,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// : declype(...)
DeclSpec DS(AttrFactory);
// : template_name<...>
ParsedType TemplateTypeTy;
TypeResult TemplateTypeTy;

if (Tok.is(tok::identifier)) {
// Get the identifier. This may be a member name or a class name,
Expand All @@ -3532,8 +3529,6 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = getTypeAnnotation(Tok);
ConsumeAnnotationToken();
if (!TemplateTypeTy)
return true;
} else {
Diag(Tok, diag::err_expected_member_or_base_name);
return true;
Expand All @@ -3552,8 +3547,10 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
SourceLocation EllipsisLoc;
TryConsumeToken(tok::ellipsis, EllipsisLoc);

if (TemplateTypeTy.isInvalid())
return true;
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
TemplateTypeTy.get(), DS, IdLoc,
InitList.get(), EllipsisLoc);
} else if(Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
Expand All @@ -3563,8 +3560,10 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
ExprVector ArgExprs;
CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&] {
if (TemplateTypeTy.isInvalid())
return QualType();
QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp(
getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II,
getCurScope(), ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II,
T.getOpenLocation());
CalledSignatureHelp = true;
return PreferredType;
Expand All @@ -3585,12 +3584,17 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
SourceLocation EllipsisLoc;
TryConsumeToken(tok::ellipsis, EllipsisLoc);

if (TemplateTypeTy.isInvalid())
return true;
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
TemplateTypeTy.get(), DS, IdLoc,
T.getOpenLocation(), ArgExprs,
T.getCloseLocation(), EllipsisLoc);
}

if (TemplateTypeTy.isInvalid())
return true;

if (getLangOpts().CPlusPlus11)
return Diag(Tok, diag::err_expected_either) << tok::l_paren << tok::l_brace;
else
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1455,7 +1455,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
break;
case tok::annot_typename:
if (isStartOfObjCClassMessageMissingOpenBracket()) {
ParsedType Type = getTypeAnnotation(Tok);
TypeResult Type = getTypeAnnotation(Tok);

// Fake up a Declarator to use with ActOnTypeName.
DeclSpec DS(AttrFactory);
Expand Down
8 changes: 2 additions & 6 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2147,12 +2147,8 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {

// type-name
case tok::annot_typename: {
if (getTypeAnnotation(Tok))
DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID,
getTypeAnnotation(Tok), Policy);
else
DS.SetTypeSpecError();

DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID,
getTypeAnnotation(Tok), Policy);
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeAnnotationToken();

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Parse/ParseObjc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2978,7 +2978,7 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
InMessageExpression)
return false;

ParsedType Type;
TypeResult Type;

if (Tok.is(tok::annot_typename))
Type = getTypeAnnotation(Tok);
Expand All @@ -2988,7 +2988,8 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
else
return false;

if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) {
// FIXME: Should not be querying properties of types from the parser.
if (Type.isUsable() && Type.get().get()->isObjCObjectOrInterfaceType()) {
const Token &AfterNext = GetLookAheadToken(2);
if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
if (Tok.is(tok::identifier))
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1321,7 +1321,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
LAngleLoc, TemplateArgsPtr, RAngleLoc);

Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
setTypeAnnotation(Tok, Type);
if (SS.isNotEmpty())
Tok.setLocation(SS.getBeginLoc());
else if (TemplateKWLoc.isValid())
Expand Down Expand Up @@ -1398,7 +1398,7 @@ void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
/*IsCtorOrDtorName*/ false, IsClassName);
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
setTypeAnnotation(Tok, Type);
if (SS.isNotEmpty()) // it was a C++ qualified type name.
Tok.setLocation(SS.getBeginLoc());
// End location stays the same
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1902,7 +1902,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {

SourceLocation EndLoc = Tok.getLastLoc();
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Ty.isInvalid() ? nullptr : Ty.get());
setTypeAnnotation(Tok, Ty);
Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(TypenameLoc);
PP.AnnotateCachedTokens(Tok);
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Parser/cxx-class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ namespace ArrayMemberAccess {
}
}

namespace UndeclaredBaseTemplate {
template<class> struct imp;
template<class T> struct is_member_function_pointer : undeclared<imp<T>::member> {}; // expected-error {{unknown template name 'undeclared'}}
}

// PR11109 must appear at the end of the source file
class pr11109r3 { // expected-note{{to match this '{'}}
public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}}

0 comments on commit 3308732

Please sign in to comment.