forked from OSchip/llvm-project
PR43080: Do not build context-sensitive expressions during name classification.
Summary: We don't know what context to use until the classification result is consumed by the parser, which could happen in a different semantic context. So don't build the expression that results from name classification until we get to that point and can handle it properly. This covers everything except C++ implicit class member access, which is a little awkward to handle properly in the face of the protected member access check. But it at least fixes all the currently-filed instances of PR43080. Reviewers: efriedma Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D68896 llvm-svn: 374826
This commit is contained in:
parent
9efbc564ba
commit
7e8fe67f0e
|
@ -728,6 +728,11 @@ ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly
|
||||||
ANNOTATION(template_id) // annotation for a C++ template-id that names a
|
ANNOTATION(template_id) // annotation for a C++ template-id that names a
|
||||||
// function template specialization (not a type),
|
// function template specialization (not a type),
|
||||||
// e.g., "std::swap<int>"
|
// e.g., "std::swap<int>"
|
||||||
|
ANNOTATION(non_type) // annotation for a single non-type declaration
|
||||||
|
ANNOTATION(non_type_undeclared) // annotation for an undeclared identifier that
|
||||||
|
// was assumed to be an ADL-only function name
|
||||||
|
ANNOTATION(non_type_dependent) // annotation for an assumed non-type member of
|
||||||
|
// a dependent base class
|
||||||
ANNOTATION(primary_expr) // annotation for a primary expression
|
ANNOTATION(primary_expr) // annotation for a primary expression
|
||||||
ANNOTATION(decltype) // annotation for a decltype expression,
|
ANNOTATION(decltype) // annotation for a decltype expression,
|
||||||
// e.g., "decltype(foo.bar())"
|
// e.g., "decltype(foo.bar())"
|
||||||
|
|
|
@ -766,6 +766,22 @@ private:
|
||||||
Tok.setAnnotationValue(T.getAsOpaquePtr());
|
Tok.setAnnotationValue(T.getAsOpaquePtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NamedDecl *getNonTypeAnnotation(const Token &Tok) {
|
||||||
|
return static_cast<NamedDecl*>(Tok.getAnnotationValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setNonTypeAnnotation(Token &Tok, NamedDecl *ND) {
|
||||||
|
Tok.setAnnotationValue(ND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IdentifierInfo *getIdentifierAnnotation(const Token &Tok) {
|
||||||
|
return static_cast<IdentifierInfo*>(Tok.getAnnotationValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setIdentifierAnnotation(Token &Tok, IdentifierInfo *ND) {
|
||||||
|
Tok.setAnnotationValue(ND);
|
||||||
|
}
|
||||||
|
|
||||||
/// Read an already-translated primary expression out of an annotation
|
/// Read an already-translated primary expression out of an annotation
|
||||||
/// token.
|
/// token.
|
||||||
static ExprResult getExprAnnotation(const Token &Tok) {
|
static ExprResult getExprAnnotation(const Token &Tok) {
|
||||||
|
@ -799,8 +815,7 @@ private:
|
||||||
/// Annotation was successful.
|
/// Annotation was successful.
|
||||||
ANK_Success
|
ANK_Success
|
||||||
};
|
};
|
||||||
AnnotatedNameKind TryAnnotateName(bool IsAddressOfOperand,
|
AnnotatedNameKind TryAnnotateName(CorrectionCandidateCallback *CCC = nullptr);
|
||||||
CorrectionCandidateCallback *CCC = nullptr);
|
|
||||||
|
|
||||||
/// Push a tok::annot_cxxscope token onto the token stream.
|
/// Push a tok::annot_cxxscope token onto the token stream.
|
||||||
void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
|
void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
|
||||||
|
|
|
@ -1855,29 +1855,52 @@ public:
|
||||||
/// Describes the result of the name lookup and resolution performed
|
/// Describes the result of the name lookup and resolution performed
|
||||||
/// by \c ClassifyName().
|
/// by \c ClassifyName().
|
||||||
enum NameClassificationKind {
|
enum NameClassificationKind {
|
||||||
|
/// This name is not a type or template in this context, but might be
|
||||||
|
/// something else.
|
||||||
NC_Unknown,
|
NC_Unknown,
|
||||||
|
/// Classification failed; an error has been produced.
|
||||||
NC_Error,
|
NC_Error,
|
||||||
|
/// The name has been typo-corrected to a keyword.
|
||||||
NC_Keyword,
|
NC_Keyword,
|
||||||
|
/// The name was classified as a type.
|
||||||
NC_Type,
|
NC_Type,
|
||||||
NC_Expression,
|
/// The name was classified as a specific non-type, non-template
|
||||||
NC_NestedNameSpecifier,
|
/// declaration. ActOnNameClassifiedAsNonType should be called to
|
||||||
|
/// convert the declaration to an expression.
|
||||||
|
NC_NonType,
|
||||||
|
/// The name was classified as an ADL-only function name.
|
||||||
|
/// ActOnNameClassifiedAsUndeclaredNonType should be called to convert the
|
||||||
|
/// result to an expression.
|
||||||
|
NC_UndeclaredNonType,
|
||||||
|
/// The name denotes a member of a dependent type that could not be
|
||||||
|
/// resolved. ActOnNameClassifiedAsDependentNonType should be called to
|
||||||
|
/// convert the result to an expression.
|
||||||
|
NC_DependentNonType,
|
||||||
|
/// The name was classified as a non-type, and an expression representing
|
||||||
|
/// that name has been formed.
|
||||||
|
NC_ContextIndependentExpr,
|
||||||
|
/// The name was classified as a template whose specializations are types.
|
||||||
NC_TypeTemplate,
|
NC_TypeTemplate,
|
||||||
|
/// The name was classified as a variable template name.
|
||||||
NC_VarTemplate,
|
NC_VarTemplate,
|
||||||
|
/// The name was classified as a function template name.
|
||||||
NC_FunctionTemplate,
|
NC_FunctionTemplate,
|
||||||
|
/// The name was classified as an ADL-only function template name.
|
||||||
NC_UndeclaredTemplate,
|
NC_UndeclaredTemplate,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NameClassification {
|
class NameClassification {
|
||||||
NameClassificationKind Kind;
|
NameClassificationKind Kind;
|
||||||
ExprResult Expr;
|
union {
|
||||||
TemplateName Template;
|
ExprResult Expr;
|
||||||
ParsedType Type;
|
NamedDecl *NonTypeDecl;
|
||||||
|
TemplateName Template;
|
||||||
|
ParsedType Type;
|
||||||
|
};
|
||||||
|
|
||||||
explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
|
explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {}
|
|
||||||
|
|
||||||
NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
|
NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
|
||||||
|
|
||||||
NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {}
|
NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {}
|
||||||
|
@ -1890,8 +1913,24 @@ public:
|
||||||
return NameClassification(NC_Unknown);
|
return NameClassification(NC_Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NameClassification NestedNameSpecifier() {
|
static NameClassification ContextIndependentExpr(ExprResult E) {
|
||||||
return NameClassification(NC_NestedNameSpecifier);
|
NameClassification Result(NC_ContextIndependentExpr);
|
||||||
|
Result.Expr = E;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NameClassification NonType(NamedDecl *D) {
|
||||||
|
NameClassification Result(NC_NonType);
|
||||||
|
Result.NonTypeDecl = D;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NameClassification UndeclaredNonType() {
|
||||||
|
return NameClassification(NC_UndeclaredNonType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NameClassification DependentNonType() {
|
||||||
|
return NameClassification(NC_DependentNonType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NameClassification TypeTemplate(TemplateName Name) {
|
static NameClassification TypeTemplate(TemplateName Name) {
|
||||||
|
@ -1920,14 +1959,19 @@ public:
|
||||||
|
|
||||||
NameClassificationKind getKind() const { return Kind; }
|
NameClassificationKind getKind() const { return Kind; }
|
||||||
|
|
||||||
|
ExprResult getExpression() const {
|
||||||
|
assert(Kind == NC_ContextIndependentExpr);
|
||||||
|
return Expr;
|
||||||
|
}
|
||||||
|
|
||||||
ParsedType getType() const {
|
ParsedType getType() const {
|
||||||
assert(Kind == NC_Type);
|
assert(Kind == NC_Type);
|
||||||
return Type;
|
return Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult getExpression() const {
|
NamedDecl *getNonTypeDecl() const {
|
||||||
assert(Kind == NC_Expression);
|
assert(Kind == NC_NonType);
|
||||||
return Expr;
|
return NonTypeDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateName getTemplateName() const {
|
TemplateName getTemplateName() const {
|
||||||
|
@ -1971,17 +2015,29 @@ public:
|
||||||
/// \param NextToken The token following the identifier. Used to help
|
/// \param NextToken The token following the identifier. Used to help
|
||||||
/// disambiguate the name.
|
/// disambiguate the name.
|
||||||
///
|
///
|
||||||
/// \param IsAddressOfOperand True if this name is the operand of a unary
|
|
||||||
/// address of ('&') expression, assuming it is classified as an
|
|
||||||
/// expression.
|
|
||||||
///
|
|
||||||
/// \param CCC The correction callback, if typo correction is desired.
|
/// \param CCC The correction callback, if typo correction is desired.
|
||||||
NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS,
|
NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS,
|
||||||
IdentifierInfo *&Name, SourceLocation NameLoc,
|
IdentifierInfo *&Name, SourceLocation NameLoc,
|
||||||
const Token &NextToken,
|
const Token &NextToken,
|
||||||
bool IsAddressOfOperand,
|
|
||||||
CorrectionCandidateCallback *CCC = nullptr);
|
CorrectionCandidateCallback *CCC = nullptr);
|
||||||
|
|
||||||
|
/// Act on the result of classifying a name as an undeclared (ADL-only)
|
||||||
|
/// non-type declaration.
|
||||||
|
ExprResult ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name,
|
||||||
|
SourceLocation NameLoc);
|
||||||
|
/// Act on the result of classifying a name as an undeclared member of a
|
||||||
|
/// dependent base class.
|
||||||
|
ExprResult ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS,
|
||||||
|
IdentifierInfo *Name,
|
||||||
|
SourceLocation NameLoc,
|
||||||
|
bool IsAddressOfOperand);
|
||||||
|
/// Act on the result of classifying a name as a specific non-type
|
||||||
|
/// declaration.
|
||||||
|
ExprResult ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
|
||||||
|
NamedDecl *Found,
|
||||||
|
SourceLocation NameLoc,
|
||||||
|
const Token &NextToken);
|
||||||
|
|
||||||
/// Describes the detailed kind of a template name. Used in diagnostics.
|
/// Describes the detailed kind of a template name. Used in diagnostics.
|
||||||
enum class TemplateNameKindForDiagnostics {
|
enum class TemplateNameKindForDiagnostics {
|
||||||
ClassTemplate,
|
ClassTemplate,
|
||||||
|
@ -3407,6 +3463,7 @@ public:
|
||||||
LookupNameKind NameKind,
|
LookupNameKind NameKind,
|
||||||
RedeclarationKind Redecl
|
RedeclarationKind Redecl
|
||||||
= NotForRedeclaration);
|
= NotForRedeclaration);
|
||||||
|
bool LookupBuiltin(LookupResult &R);
|
||||||
bool LookupName(LookupResult &R, Scope *S,
|
bool LookupName(LookupResult &R, Scope *S,
|
||||||
bool AllowBuiltinCreation = false);
|
bool AllowBuiltinCreation = false);
|
||||||
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
|
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
|
||||||
|
@ -4389,6 +4446,10 @@ public:
|
||||||
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
|
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
|
||||||
ArrayRef<Expr *> Args = None, TypoExpr **Out = nullptr);
|
ArrayRef<Expr *> Args = None, TypoExpr **Out = nullptr);
|
||||||
|
|
||||||
|
DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||||
|
IdentifierInfo *II);
|
||||||
|
ExprResult BuildIvarRefExpr(Scope *S, SourceLocation Loc, ObjCIvarDecl *IV);
|
||||||
|
|
||||||
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
|
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
|
||||||
IdentifierInfo *II,
|
IdentifierInfo *II,
|
||||||
bool AllowBuiltinCreation=false);
|
bool AllowBuiltinCreation=false);
|
||||||
|
|
|
@ -2929,28 +2929,29 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
|
||||||
IdentifierInfo *Name = AfterScope.getIdentifierInfo();
|
IdentifierInfo *Name = AfterScope.getIdentifierInfo();
|
||||||
Sema::NameClassification Classification = Actions.ClassifyName(
|
Sema::NameClassification Classification = Actions.ClassifyName(
|
||||||
getCurScope(), SS, Name, AfterScope.getLocation(), Next,
|
getCurScope(), SS, Name, AfterScope.getLocation(), Next,
|
||||||
/*IsAddressOfOperand=*/false, /*CCC=*/nullptr);
|
/*CCC=*/nullptr);
|
||||||
switch (Classification.getKind()) {
|
switch (Classification.getKind()) {
|
||||||
case Sema::NC_Error:
|
case Sema::NC_Error:
|
||||||
SkipMalformedDecl();
|
SkipMalformedDecl();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Sema::NC_Keyword:
|
case Sema::NC_Keyword:
|
||||||
case Sema::NC_NestedNameSpecifier:
|
llvm_unreachable("typo correction is not possible here");
|
||||||
llvm_unreachable("typo correction and nested name specifiers not "
|
|
||||||
"possible here");
|
|
||||||
|
|
||||||
case Sema::NC_Type:
|
case Sema::NC_Type:
|
||||||
case Sema::NC_TypeTemplate:
|
case Sema::NC_TypeTemplate:
|
||||||
|
case Sema::NC_UndeclaredNonType:
|
||||||
|
case Sema::NC_UndeclaredTemplate:
|
||||||
// Not a previously-declared non-type entity.
|
// Not a previously-declared non-type entity.
|
||||||
MightBeDeclarator = false;
|
MightBeDeclarator = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Sema::NC_Unknown:
|
case Sema::NC_Unknown:
|
||||||
case Sema::NC_Expression:
|
case Sema::NC_NonType:
|
||||||
|
case Sema::NC_DependentNonType:
|
||||||
|
case Sema::NC_ContextIndependentExpr:
|
||||||
case Sema::NC_VarTemplate:
|
case Sema::NC_VarTemplate:
|
||||||
case Sema::NC_FunctionTemplate:
|
case Sema::NC_FunctionTemplate:
|
||||||
case Sema::NC_UndeclaredTemplate:
|
|
||||||
// Might be a redeclaration of a prior entity.
|
// Might be a redeclaration of a prior entity.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,13 +840,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
|
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
|
||||||
|
|
||||||
case tok::annot_primary_expr:
|
case tok::annot_primary_expr:
|
||||||
assert(Res.get() == nullptr && "Stray primary-expression annotation?");
|
|
||||||
Res = getExprAnnotation(Tok);
|
Res = getExprAnnotation(Tok);
|
||||||
ConsumeAnnotationToken();
|
ConsumeAnnotationToken();
|
||||||
if (!Res.isInvalid() && Tok.is(tok::less))
|
if (!Res.isInvalid() && Tok.is(tok::less))
|
||||||
checkPotentialAngleBracket(Res);
|
checkPotentialAngleBracket(Res);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case tok::annot_non_type:
|
||||||
|
case tok::annot_non_type_dependent:
|
||||||
|
case tok::annot_non_type_undeclared: {
|
||||||
|
CXXScopeSpec SS;
|
||||||
|
Token Replacement;
|
||||||
|
Res = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
|
||||||
|
assert(!Res.isUnset() &&
|
||||||
|
"should not perform typo correction on annotation token");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case tok::kw___super:
|
case tok::kw___super:
|
||||||
case tok::kw_decltype:
|
case tok::kw_decltype:
|
||||||
// Annotate the token and tail recurse.
|
// Annotate the token and tail recurse.
|
||||||
|
|
|
@ -555,27 +555,66 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
|
ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
|
||||||
|
bool isAddressOfOperand,
|
||||||
Token &Replacement) {
|
Token &Replacement) {
|
||||||
SourceLocation TemplateKWLoc;
|
ExprResult E;
|
||||||
UnqualifiedId Name;
|
|
||||||
if (ParseUnqualifiedId(SS,
|
|
||||||
/*EnteringContext=*/false,
|
|
||||||
/*AllowDestructorName=*/false,
|
|
||||||
/*AllowConstructorName=*/false,
|
|
||||||
/*AllowDeductionGuide=*/false,
|
|
||||||
/*ObjectType=*/nullptr, &TemplateKWLoc, Name))
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// This is only the direct operand of an & operator if it is not
|
// We may have already annotated this id-expression.
|
||||||
// followed by a postfix-expression suffix.
|
switch (Tok.getKind()) {
|
||||||
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
|
case tok::annot_non_type: {
|
||||||
isAddressOfOperand = false;
|
NamedDecl *ND = getNonTypeAnnotation(Tok);
|
||||||
|
SourceLocation Loc = ConsumeAnnotationToken();
|
||||||
|
E = Actions.ActOnNameClassifiedAsNonType(getCurScope(), SS, ND, Loc, Tok);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case tok::annot_non_type_dependent: {
|
||||||
|
IdentifierInfo *II = getIdentifierAnnotation(Tok);
|
||||||
|
SourceLocation Loc = ConsumeAnnotationToken();
|
||||||
|
|
||||||
|
// This is only the direct operand of an & operator if it is not
|
||||||
|
// followed by a postfix-expression suffix.
|
||||||
|
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
|
||||||
|
isAddressOfOperand = false;
|
||||||
|
|
||||||
|
E = Actions.ActOnNameClassifiedAsDependentNonType(SS, II, Loc,
|
||||||
|
isAddressOfOperand);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case tok::annot_non_type_undeclared: {
|
||||||
|
assert(SS.isEmpty() &&
|
||||||
|
"undeclared non-type annotation should be unqualified");
|
||||||
|
IdentifierInfo *II = getIdentifierAnnotation(Tok);
|
||||||
|
SourceLocation Loc = ConsumeAnnotationToken();
|
||||||
|
E = Actions.ActOnNameClassifiedAsUndeclaredNonType(II, Loc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
SourceLocation TemplateKWLoc;
|
||||||
|
UnqualifiedId Name;
|
||||||
|
if (ParseUnqualifiedId(SS,
|
||||||
|
/*EnteringContext=*/false,
|
||||||
|
/*AllowDestructorName=*/false,
|
||||||
|
/*AllowConstructorName=*/false,
|
||||||
|
/*AllowDeductionGuide=*/false,
|
||||||
|
/*ObjectType=*/nullptr, &TemplateKWLoc, Name))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
// This is only the direct operand of an & operator if it is not
|
||||||
|
// followed by a postfix-expression suffix.
|
||||||
|
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
|
||||||
|
isAddressOfOperand = false;
|
||||||
|
|
||||||
|
E = Actions.ActOnIdExpression(
|
||||||
|
getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
|
||||||
|
isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false,
|
||||||
|
&Replacement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ExprResult E = Actions.ActOnIdExpression(
|
|
||||||
getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
|
|
||||||
isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false,
|
|
||||||
&Replacement);
|
|
||||||
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
|
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
|
||||||
checkPotentialAngleBracket(E);
|
checkPotentialAngleBracket(E);
|
||||||
return E;
|
return E;
|
||||||
|
|
|
@ -187,7 +187,7 @@ Retry:
|
||||||
// Try to limit which sets of keywords should be included in typo
|
// Try to limit which sets of keywords should be included in typo
|
||||||
// correction based on what the next token is.
|
// correction based on what the next token is.
|
||||||
StatementFilterCCC CCC(Next);
|
StatementFilterCCC CCC(Next);
|
||||||
if (TryAnnotateName(/*IsAddressOfOperand*/ false, &CCC) == ANK_Error) {
|
if (TryAnnotateName(&CCC) == ANK_Error) {
|
||||||
// Handle errors here by skipping up to the next semicolon or '}', and
|
// Handle errors here by skipping up to the next semicolon or '}', and
|
||||||
// eat the semicolon if that's what stopped us.
|
// eat the semicolon if that's what stopped us.
|
||||||
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
||||||
|
|
|
@ -1330,7 +1330,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
||||||
// this is ambiguous. Typo-correct to type and expression keywords and
|
// this is ambiguous. Typo-correct to type and expression keywords and
|
||||||
// to types and identifiers, in order to try to recover from errors.
|
// to types and identifiers, in order to try to recover from errors.
|
||||||
TentativeParseCCC CCC(Next);
|
TentativeParseCCC CCC(Next);
|
||||||
switch (TryAnnotateName(false /* no nested name specifier */, &CCC)) {
|
switch (TryAnnotateName(&CCC)) {
|
||||||
case ANK_Error:
|
case ANK_Error:
|
||||||
return TPResult::Error;
|
return TPResult::Error;
|
||||||
case ANK_TentativeDecl:
|
case ANK_TentativeDecl:
|
||||||
|
@ -1569,7 +1569,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
||||||
} else {
|
} else {
|
||||||
// Try to resolve the name. If it doesn't exist, assume it was
|
// Try to resolve the name. If it doesn't exist, assume it was
|
||||||
// intended to name a type and keep disambiguating.
|
// intended to name a type and keep disambiguating.
|
||||||
switch (TryAnnotateName(false /* SS is not dependent */)) {
|
switch (TryAnnotateName()) {
|
||||||
case ANK_Error:
|
case ANK_Error:
|
||||||
return TPResult::Error;
|
return TPResult::Error;
|
||||||
case ANK_TentativeDecl:
|
case ANK_TentativeDecl:
|
||||||
|
|
|
@ -1561,13 +1561,10 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
|
||||||
/// with a typo-corrected keyword. This is only appropriate when the current
|
/// with a typo-corrected keyword. This is only appropriate when the current
|
||||||
/// name must refer to an entity which has already been declared.
|
/// name must refer to an entity which has already been declared.
|
||||||
///
|
///
|
||||||
/// \param IsAddressOfOperand Must be \c true if the name is preceded by an '&'
|
|
||||||
/// and might possibly have a dependent nested name specifier.
|
|
||||||
/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
|
/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
|
||||||
/// no typo correction will be performed.
|
/// no typo correction will be performed.
|
||||||
Parser::AnnotatedNameKind
|
Parser::AnnotatedNameKind
|
||||||
Parser::TryAnnotateName(bool IsAddressOfOperand,
|
Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
|
||||||
CorrectionCandidateCallback *CCC) {
|
|
||||||
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
|
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
|
||||||
|
|
||||||
const bool EnteringContext = false;
|
const bool EnteringContext = false;
|
||||||
|
@ -1603,9 +1600,8 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
||||||
// after a scope specifier, because in general we can't recover from typos
|
// after a scope specifier, because in general we can't recover from typos
|
||||||
// there (eg, after correcting 'A::template B<X>::C' [sic], we would need to
|
// there (eg, after correcting 'A::template B<X>::C' [sic], we would need to
|
||||||
// jump back into scope specifier parsing).
|
// jump back into scope specifier parsing).
|
||||||
Sema::NameClassification Classification =
|
Sema::NameClassification Classification = Actions.ClassifyName(
|
||||||
Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
|
getCurScope(), SS, Name, NameLoc, Next, SS.isEmpty() ? CCC : nullptr);
|
||||||
IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
|
|
||||||
|
|
||||||
// If name lookup found nothing and we guessed that this was a template name,
|
// If name lookup found nothing and we guessed that this was a template name,
|
||||||
// double-check before committing to that interpretation. C++20 requires that
|
// double-check before committing to that interpretation. C++20 requires that
|
||||||
|
@ -1618,7 +1614,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
||||||
FakeNext.setKind(tok::unknown);
|
FakeNext.setKind(tok::unknown);
|
||||||
Classification =
|
Classification =
|
||||||
Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, FakeNext,
|
Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, FakeNext,
|
||||||
IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
|
SS.isEmpty() ? CCC : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Classification.getKind()) {
|
switch (Classification.getKind()) {
|
||||||
|
@ -1671,7 +1667,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
||||||
return ANK_Success;
|
return ANK_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Sema::NC_Expression:
|
case Sema::NC_ContextIndependentExpr:
|
||||||
Tok.setKind(tok::annot_primary_expr);
|
Tok.setKind(tok::annot_primary_expr);
|
||||||
setExprAnnotation(Tok, Classification.getExpression());
|
setExprAnnotation(Tok, Classification.getExpression());
|
||||||
Tok.setAnnotationEndLoc(NameLoc);
|
Tok.setAnnotationEndLoc(NameLoc);
|
||||||
|
@ -1680,6 +1676,29 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
||||||
PP.AnnotateCachedTokens(Tok);
|
PP.AnnotateCachedTokens(Tok);
|
||||||
return ANK_Success;
|
return ANK_Success;
|
||||||
|
|
||||||
|
case Sema::NC_NonType:
|
||||||
|
Tok.setKind(tok::annot_non_type);
|
||||||
|
setNonTypeAnnotation(Tok, Classification.getNonTypeDecl());
|
||||||
|
Tok.setLocation(NameLoc);
|
||||||
|
Tok.setAnnotationEndLoc(NameLoc);
|
||||||
|
PP.AnnotateCachedTokens(Tok);
|
||||||
|
if (SS.isNotEmpty())
|
||||||
|
AnnotateScopeToken(SS, !WasScopeAnnotation);
|
||||||
|
return ANK_Success;
|
||||||
|
|
||||||
|
case Sema::NC_UndeclaredNonType:
|
||||||
|
case Sema::NC_DependentNonType:
|
||||||
|
Tok.setKind(Classification.getKind() == Sema::NC_UndeclaredNonType
|
||||||
|
? tok::annot_non_type_undeclared
|
||||||
|
: tok::annot_non_type_dependent);
|
||||||
|
setIdentifierAnnotation(Tok, Name);
|
||||||
|
Tok.setLocation(NameLoc);
|
||||||
|
Tok.setAnnotationEndLoc(NameLoc);
|
||||||
|
PP.AnnotateCachedTokens(Tok);
|
||||||
|
if (SS.isNotEmpty())
|
||||||
|
AnnotateScopeToken(SS, !WasScopeAnnotation);
|
||||||
|
return ANK_Success;
|
||||||
|
|
||||||
case Sema::NC_TypeTemplate:
|
case Sema::NC_TypeTemplate:
|
||||||
if (Next.isNot(tok::less)) {
|
if (Next.isNot(tok::less)) {
|
||||||
// This may be a type template being used as a template template argument.
|
// This may be a type template being used as a template template argument.
|
||||||
|
@ -1701,9 +1720,6 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
||||||
return ANK_Error;
|
return ANK_Error;
|
||||||
return ANK_Success;
|
return ANK_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Sema::NC_NestedNameSpecifier:
|
|
||||||
llvm_unreachable("already parsed nested name specifier");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unable to classify the name, but maybe we can annotate a scope specifier.
|
// Unable to classify the name, but maybe we can annotate a scope specifier.
|
||||||
|
|
|
@ -845,18 +845,18 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
|
||||||
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
|
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
|
||||||
}
|
}
|
||||||
|
|
||||||
Sema::NameClassification
|
Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
|
||||||
Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
|
IdentifierInfo *&Name,
|
||||||
SourceLocation NameLoc, const Token &NextToken,
|
SourceLocation NameLoc,
|
||||||
bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) {
|
const Token &NextToken,
|
||||||
|
CorrectionCandidateCallback *CCC) {
|
||||||
DeclarationNameInfo NameInfo(Name, NameLoc);
|
DeclarationNameInfo NameInfo(Name, NameLoc);
|
||||||
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
||||||
|
|
||||||
if (NextToken.is(tok::coloncolon)) {
|
assert(NextToken.isNot(tok::coloncolon) &&
|
||||||
NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation());
|
"parse nested name specifiers before calling ClassifyName");
|
||||||
BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false);
|
if (getLangOpts().CPlusPlus && SS.isSet() &&
|
||||||
} else if (getLangOpts().CPlusPlus && SS.isSet() &&
|
isCurrentClassName(*Name, S, &SS)) {
|
||||||
isCurrentClassName(*Name, S, &SS)) {
|
|
||||||
// Per [class.qual]p2, this names the constructors of SS, not the
|
// Per [class.qual]p2, this names the constructors of SS, not the
|
||||||
// injected-class-name. We don't have a classification for that.
|
// injected-class-name. We don't have a classification for that.
|
||||||
// There's not much point caching this result, since the parser
|
// There's not much point caching this result, since the parser
|
||||||
|
@ -880,9 +880,15 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
|
||||||
// FIXME: This lookup really, really needs to be folded in to the normal
|
// FIXME: This lookup really, really needs to be folded in to the normal
|
||||||
// unqualified lookup mechanism.
|
// unqualified lookup mechanism.
|
||||||
if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
|
if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
|
||||||
ExprResult E = LookupInObjCMethod(Result, S, Name, true);
|
DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name);
|
||||||
if (E.get() || E.isInvalid())
|
if (Ivar.isInvalid())
|
||||||
return E;
|
return NameClassification::Error();
|
||||||
|
if (Ivar.isUsable())
|
||||||
|
return NameClassification::NonType(cast<NamedDecl>(Ivar.get()));
|
||||||
|
|
||||||
|
// We defer builtin creation until after ivar lookup inside ObjC methods.
|
||||||
|
if (Result.empty())
|
||||||
|
LookupBuiltin(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SecondTry = false;
|
bool SecondTry = false;
|
||||||
|
@ -897,7 +903,7 @@ Corrected:
|
||||||
// In C++, this is an ADL-only call.
|
// In C++, this is an ADL-only call.
|
||||||
// FIXME: Reference?
|
// FIXME: Reference?
|
||||||
if (getLangOpts().CPlusPlus)
|
if (getLangOpts().CPlusPlus)
|
||||||
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
|
return NameClassification::UndeclaredNonType();
|
||||||
|
|
||||||
// C90 6.3.2.2:
|
// C90 6.3.2.2:
|
||||||
// If the expression that precedes the parenthesized argument list in a
|
// If the expression that precedes the parenthesized argument list in a
|
||||||
|
@ -911,11 +917,8 @@ Corrected:
|
||||||
// appeared.
|
// appeared.
|
||||||
//
|
//
|
||||||
// We also allow this in C99 as an extension.
|
// We also allow this in C99 as an extension.
|
||||||
if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
|
if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S))
|
||||||
Result.addDecl(D);
|
return NameClassification::NonType(D);
|
||||||
Result.resolveKind();
|
|
||||||
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
|
if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
|
||||||
|
@ -990,9 +993,12 @@ Corrected:
|
||||||
// reference the ivar.
|
// reference the ivar.
|
||||||
// FIXME: This is a gross hack.
|
// FIXME: This is a gross hack.
|
||||||
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
|
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
|
||||||
Result.clear();
|
DeclResult R =
|
||||||
ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
|
LookupIvarInObjCMethod(Result, S, Ivar->getIdentifier());
|
||||||
return E;
|
if (R.isInvalid())
|
||||||
|
return NameClassification::Error();
|
||||||
|
if (R.isUsable())
|
||||||
|
return NameClassification::NonType(Ivar);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto Corrected;
|
goto Corrected;
|
||||||
|
@ -1018,9 +1024,7 @@ Corrected:
|
||||||
// perform some heroics to see if we actually have a
|
// perform some heroics to see if we actually have a
|
||||||
// template-argument-list, which would indicate a missing 'template'
|
// template-argument-list, which would indicate a missing 'template'
|
||||||
// keyword here.
|
// keyword here.
|
||||||
return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
|
return NameClassification::DependentNonType();
|
||||||
NameInfo, IsAddressOfOperand,
|
|
||||||
/*TemplateArgs=*/nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case LookupResult::Found:
|
case LookupResult::Found:
|
||||||
|
@ -1167,9 +1171,57 @@ Corrected:
|
||||||
return ParsedType::make(T);
|
return ParsedType::make(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This is context-dependent. We need to defer building the member
|
||||||
|
// expression until the classification is consumed.
|
||||||
if (FirstDecl->isCXXClassMember())
|
if (FirstDecl->isCXXClassMember())
|
||||||
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
|
return NameClassification::ContextIndependentExpr(
|
||||||
nullptr, S);
|
BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr,
|
||||||
|
S));
|
||||||
|
|
||||||
|
// If we already know which single declaration is referenced, just annotate
|
||||||
|
// that declaration directly.
|
||||||
|
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
|
||||||
|
if (Result.isSingleResult() && !ADL)
|
||||||
|
return NameClassification::NonType(Result.getRepresentativeDecl());
|
||||||
|
|
||||||
|
// Build an UnresolvedLookupExpr. Note that this doesn't depend on the
|
||||||
|
// context in which we performed classification, so it's safe to do now.
|
||||||
|
return NameClassification::ContextIndependentExpr(
|
||||||
|
BuildDeclarationNameExpr(SS, Result, ADL));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprResult
|
||||||
|
Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name,
|
||||||
|
SourceLocation NameLoc) {
|
||||||
|
assert(getLangOpts().CPlusPlus && "ADL-only call in C?");
|
||||||
|
CXXScopeSpec SS;
|
||||||
|
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
|
||||||
|
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprResult
|
||||||
|
Sema::ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS,
|
||||||
|
IdentifierInfo *Name,
|
||||||
|
SourceLocation NameLoc,
|
||||||
|
bool IsAddressOfOperand) {
|
||||||
|
DeclarationNameInfo NameInfo(Name, NameLoc);
|
||||||
|
return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
|
||||||
|
NameInfo, IsAddressOfOperand,
|
||||||
|
/*TemplateArgs=*/nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
|
||||||
|
NamedDecl *Found,
|
||||||
|
SourceLocation NameLoc,
|
||||||
|
const Token &NextToken) {
|
||||||
|
if (getCurMethodDecl() && SS.isEmpty())
|
||||||
|
if (auto *Ivar = dyn_cast<ObjCIvarDecl>(Found->getUnderlyingDecl()))
|
||||||
|
return BuildIvarRefExpr(S, NameLoc, Ivar);
|
||||||
|
|
||||||
|
// Reconstruct the lookup result.
|
||||||
|
LookupResult Result(*this, Found->getDeclName(), NameLoc, LookupOrdinaryName);
|
||||||
|
Result.addDecl(Found);
|
||||||
|
Result.resolveKind();
|
||||||
|
|
||||||
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
|
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
|
||||||
return BuildDeclarationNameExpr(SS, Result, ADL);
|
return BuildDeclarationNameExpr(SS, Result, ADL);
|
||||||
|
|
|
@ -2482,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
|
||||||
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
|
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LookupInObjCMethod - The parser has read a name in, and Sema has
|
/// The parser has read a name in, and Sema has detected that we're currently
|
||||||
/// detected that we're currently inside an ObjC method. Perform some
|
/// inside an ObjC method. Perform some additional checks and determine if we
|
||||||
/// additional lookup.
|
/// should form a reference to an ivar.
|
||||||
///
|
///
|
||||||
/// Ideally, most of this would be done by lookup, but there's
|
/// Ideally, most of this would be done by lookup, but there's
|
||||||
/// actually quite a lot of extra work involved.
|
/// actually quite a lot of extra work involved.
|
||||||
///
|
DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||||
/// Returns a null sentinel to indicate trivial success.
|
IdentifierInfo *II) {
|
||||||
ExprResult
|
|
||||||
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
|
||||||
IdentifierInfo *II, bool AllowBuiltinCreation) {
|
|
||||||
SourceLocation Loc = Lookup.getNameLoc();
|
SourceLocation Loc = Lookup.getNameLoc();
|
||||||
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
||||||
|
|
||||||
// Check for error condition which is already reported.
|
// Check for error condition which is already reported.
|
||||||
if (!CurMethod)
|
if (!CurMethod)
|
||||||
return ExprError();
|
return DeclResult(true);
|
||||||
|
|
||||||
// There are two cases to handle here. 1) scoped lookup could have failed,
|
// There are two cases to handle here. 1) scoped lookup could have failed,
|
||||||
// in which case we should look for an ivar. 2) scoped lookup could have
|
// in which case we should look for an ivar. 2) scoped lookup could have
|
||||||
|
@ -2526,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||||
ObjCIvarDecl *IV = nullptr;
|
ObjCIvarDecl *IV = nullptr;
|
||||||
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
|
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
|
||||||
// Diagnose using an ivar in a class method.
|
// Diagnose using an ivar in a class method.
|
||||||
if (IsClassMethod)
|
if (IsClassMethod) {
|
||||||
return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
|
Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
|
||||||
<< IV->getDeclName());
|
return DeclResult(true);
|
||||||
|
}
|
||||||
// If we're referencing an invalid decl, just return this as a silent
|
|
||||||
// error node. The error diagnostic was already emitted on the decl.
|
|
||||||
if (IV->isInvalidDecl())
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// Check if referencing a field with __attribute__((deprecated)).
|
|
||||||
if (DiagnoseUseOfDecl(IV, Loc))
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// Diagnose the use of an ivar outside of the declaring class.
|
// Diagnose the use of an ivar outside of the declaring class.
|
||||||
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
|
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
|
||||||
|
@ -2545,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||||
!getLangOpts().DebuggerSupport)
|
!getLangOpts().DebuggerSupport)
|
||||||
Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName();
|
Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName();
|
||||||
|
|
||||||
// FIXME: This should use a new expr for a direct reference, don't
|
// Success.
|
||||||
// turn this into Self->ivar, just return a BareIVarExpr or something.
|
return IV;
|
||||||
IdentifierInfo &II = Context.Idents.get("self");
|
|
||||||
UnqualifiedId SelfName;
|
|
||||||
SelfName.setIdentifier(&II, SourceLocation());
|
|
||||||
SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
|
|
||||||
CXXScopeSpec SelfScopeSpec;
|
|
||||||
SourceLocation TemplateKWLoc;
|
|
||||||
ExprResult SelfExpr =
|
|
||||||
ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
|
|
||||||
/*HasTrailingLParen=*/false,
|
|
||||||
/*IsAddressOfOperand=*/false);
|
|
||||||
if (SelfExpr.isInvalid())
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
SelfExpr = DefaultLvalueConversion(SelfExpr.get());
|
|
||||||
if (SelfExpr.isInvalid())
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
MarkAnyDeclReferenced(Loc, IV, true);
|
|
||||||
|
|
||||||
ObjCMethodFamily MF = CurMethod->getMethodFamily();
|
|
||||||
if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
|
|
||||||
!IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
|
|
||||||
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
|
|
||||||
|
|
||||||
ObjCIvarRefExpr *Result = new (Context)
|
|
||||||
ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
|
|
||||||
IV->getLocation(), SelfExpr.get(), true, true);
|
|
||||||
|
|
||||||
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
|
|
||||||
if (!isUnevaluatedContext() &&
|
|
||||||
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
|
|
||||||
getCurFunction()->recordUseOfWeak(Result);
|
|
||||||
}
|
|
||||||
if (getLangOpts().ObjCAutoRefCount)
|
|
||||||
if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
|
|
||||||
ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
}
|
||||||
} else if (CurMethod->isInstanceMethod()) {
|
} else if (CurMethod->isInstanceMethod()) {
|
||||||
// We should warn if a local variable hides an ivar.
|
// We should warn if a local variable hides an ivar.
|
||||||
|
@ -2599,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||||
} else if (Lookup.isSingleResult() &&
|
} else if (Lookup.isSingleResult() &&
|
||||||
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
|
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
|
||||||
// If accessing a stand-alone ivar in a class method, this is an error.
|
// If accessing a stand-alone ivar in a class method, this is an error.
|
||||||
if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl()))
|
if (const ObjCIvarDecl *IV =
|
||||||
return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
|
dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) {
|
||||||
<< IV->getDeclName());
|
Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
|
||||||
}
|
return DeclResult(true);
|
||||||
|
|
||||||
if (Lookup.empty() && II && AllowBuiltinCreation) {
|
|
||||||
// FIXME. Consolidate this with similar code in LookupName.
|
|
||||||
if (unsigned BuiltinID = II->getBuiltinID()) {
|
|
||||||
if (!(getLangOpts().CPlusPlus &&
|
|
||||||
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
|
|
||||||
NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
|
|
||||||
S, Lookup.isForRedeclaration(),
|
|
||||||
Lookup.getNameLoc());
|
|
||||||
if (D) Lookup.addDecl(D);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Didn't encounter an error, didn't find an ivar.
|
||||||
|
return DeclResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc,
|
||||||
|
ObjCIvarDecl *IV) {
|
||||||
|
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
||||||
|
assert(CurMethod && CurMethod->isInstanceMethod() &&
|
||||||
|
"should not reference ivar from this context");
|
||||||
|
|
||||||
|
ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
|
||||||
|
assert(IFace && "should not reference ivar from this context");
|
||||||
|
|
||||||
|
// If we're referencing an invalid decl, just return this as a silent
|
||||||
|
// error node. The error diagnostic was already emitted on the decl.
|
||||||
|
if (IV->isInvalidDecl())
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
// Check if referencing a field with __attribute__((deprecated)).
|
||||||
|
if (DiagnoseUseOfDecl(IV, Loc))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
// FIXME: This should use a new expr for a direct reference, don't
|
||||||
|
// turn this into Self->ivar, just return a BareIVarExpr or something.
|
||||||
|
IdentifierInfo &II = Context.Idents.get("self");
|
||||||
|
UnqualifiedId SelfName;
|
||||||
|
SelfName.setIdentifier(&II, SourceLocation());
|
||||||
|
SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
|
||||||
|
CXXScopeSpec SelfScopeSpec;
|
||||||
|
SourceLocation TemplateKWLoc;
|
||||||
|
ExprResult SelfExpr =
|
||||||
|
ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
|
||||||
|
/*HasTrailingLParen=*/false,
|
||||||
|
/*IsAddressOfOperand=*/false);
|
||||||
|
if (SelfExpr.isInvalid())
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
SelfExpr = DefaultLvalueConversion(SelfExpr.get());
|
||||||
|
if (SelfExpr.isInvalid())
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
MarkAnyDeclReferenced(Loc, IV, true);
|
||||||
|
|
||||||
|
ObjCMethodFamily MF = CurMethod->getMethodFamily();
|
||||||
|
if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
|
||||||
|
!IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
|
||||||
|
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
|
||||||
|
|
||||||
|
ObjCIvarRefExpr *Result = new (Context)
|
||||||
|
ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
|
||||||
|
IV->getLocation(), SelfExpr.get(), true, true);
|
||||||
|
|
||||||
|
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
|
||||||
|
if (!isUnevaluatedContext() &&
|
||||||
|
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
|
||||||
|
getCurFunction()->recordUseOfWeak(Result);
|
||||||
|
}
|
||||||
|
if (getLangOpts().ObjCAutoRefCount)
|
||||||
|
if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
|
||||||
|
ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The parser has read a name in, and Sema has detected that we're currently
|
||||||
|
/// inside an ObjC method. Perform some additional checks and determine if we
|
||||||
|
/// should form a reference to an ivar. If so, build an expression referencing
|
||||||
|
/// that ivar.
|
||||||
|
ExprResult
|
||||||
|
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||||
|
IdentifierInfo *II, bool AllowBuiltinCreation) {
|
||||||
|
// FIXME: Integrate this lookup step into LookupParsedName.
|
||||||
|
DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II);
|
||||||
|
if (Ivar.isInvalid())
|
||||||
|
return ExprError();
|
||||||
|
if (Ivar.isUsable())
|
||||||
|
return BuildIvarRefExpr(S, Lookup.getNameLoc(),
|
||||||
|
cast<ObjCIvarDecl>(Ivar.get()));
|
||||||
|
|
||||||
|
if (Lookup.empty() && II && AllowBuiltinCreation)
|
||||||
|
LookupBuiltin(Lookup);
|
||||||
|
|
||||||
// Sentinel value saying that we didn't do anything special.
|
// Sentinel value saying that we didn't do anything special.
|
||||||
return ExprResult((Expr *)nullptr);
|
return ExprResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast a base object to a member's actual type.
|
/// Cast a base object to a member's actual type.
|
||||||
|
|
|
@ -826,7 +826,7 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
|
||||||
|
|
||||||
/// Lookup a builtin function, when name lookup would otherwise
|
/// Lookup a builtin function, when name lookup would otherwise
|
||||||
/// fail.
|
/// fail.
|
||||||
static bool LookupBuiltin(Sema &S, LookupResult &R) {
|
bool Sema::LookupBuiltin(LookupResult &R) {
|
||||||
Sema::LookupNameKind NameKind = R.getLookupKind();
|
Sema::LookupNameKind NameKind = R.getLookupKind();
|
||||||
|
|
||||||
// If we didn't find a use of this identifier, and if the identifier
|
// If we didn't find a use of this identifier, and if the identifier
|
||||||
|
@ -836,21 +836,21 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
|
||||||
NameKind == Sema::LookupRedeclarationWithLinkage) {
|
NameKind == Sema::LookupRedeclarationWithLinkage) {
|
||||||
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
|
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
|
||||||
if (II) {
|
if (II) {
|
||||||
if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
|
if (getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
|
||||||
if (II == S.getASTContext().getMakeIntegerSeqName()) {
|
if (II == getASTContext().getMakeIntegerSeqName()) {
|
||||||
R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
|
R.addDecl(getASTContext().getMakeIntegerSeqDecl());
|
||||||
return true;
|
return true;
|
||||||
} else if (II == S.getASTContext().getTypePackElementName()) {
|
} else if (II == getASTContext().getTypePackElementName()) {
|
||||||
R.addDecl(S.getASTContext().getTypePackElementDecl());
|
R.addDecl(getASTContext().getTypePackElementDecl());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is an OpenCL Builtin, and if so, insert its overloads.
|
// Check if this is an OpenCL Builtin, and if so, insert its overloads.
|
||||||
if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) {
|
if (getLangOpts().OpenCL && getLangOpts().DeclareOpenCLBuiltins) {
|
||||||
auto Index = isOpenCLBuiltin(II->getName());
|
auto Index = isOpenCLBuiltin(II->getName());
|
||||||
if (Index.first) {
|
if (Index.first) {
|
||||||
InsertOCLBuiltinDeclarationsFromTable(S, R, II, Index.first - 1,
|
InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1,
|
||||||
Index.second);
|
Index.second);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -860,14 +860,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
|
||||||
if (unsigned BuiltinID = II->getBuiltinID()) {
|
if (unsigned BuiltinID = II->getBuiltinID()) {
|
||||||
// In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
|
// In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
|
||||||
// library functions like 'malloc'. Instead, we'll just error.
|
// library functions like 'malloc'. Instead, we'll just error.
|
||||||
if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) &&
|
if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
|
||||||
S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
|
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II,
|
if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II,
|
||||||
BuiltinID, S.TUScope,
|
BuiltinID, TUScope,
|
||||||
R.isForRedeclaration(),
|
R.isForRedeclaration(),
|
||||||
R.getNameLoc())) {
|
R.getNameLoc())) {
|
||||||
R.addDecl(D);
|
R.addDecl(D);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1013,7 +1013,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R))
|
if (!Found && DC->isTranslationUnit() && S.LookupBuiltin(R))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (R.getLookupName().getNameKind()
|
if (R.getLookupName().getNameKind()
|
||||||
|
@ -2011,7 +2011,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
|
||||||
// If we didn't find a use of this identifier, and if the identifier
|
// If we didn't find a use of this identifier, and if the identifier
|
||||||
// corresponds to a compiler builtin, create the decl object for the builtin
|
// corresponds to a compiler builtin, create the decl object for the builtin
|
||||||
// now, injecting it into translation unit scope, and return it.
|
// now, injecting it into translation unit scope, and return it.
|
||||||
if (AllowBuiltinCreation && LookupBuiltin(*this, R))
|
if (AllowBuiltinCreation && LookupBuiltin(R))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If we didn't find a use of this identifier, the ExternalSource
|
// If we didn't find a use of this identifier, the ExternalSource
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// RUN: %clang_cc1 -emit-llvm-only %s
|
||||||
|
|
||||||
|
namespace PR43080 {
|
||||||
|
int f(int i) { return sizeof i<i; }
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace PR42861 {
|
||||||
|
const unsigned long s = alignof(int);
|
||||||
|
void foo() { alignas(s) int j; }
|
||||||
|
}
|
|
@ -16,3 +16,10 @@ void captures_invalid_array_type() {
|
||||||
auto q = [child]{};
|
auto q = [child]{};
|
||||||
const int n = sizeof(q);
|
const int n = sizeof(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pr43080(int i) { // expected-note {{declared here}}
|
||||||
|
return [] { // expected-note {{begins here}}
|
||||||
|
return sizeof i <
|
||||||
|
i; // expected-error {{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue