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
|
||||
// function template specialization (not a type),
|
||||
// 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(decltype) // annotation for a decltype expression,
|
||||
// e.g., "decltype(foo.bar())"
|
||||
|
|
|
@ -766,6 +766,22 @@ private:
|
|||
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
|
||||
/// token.
|
||||
static ExprResult getExprAnnotation(const Token &Tok) {
|
||||
|
@ -799,8 +815,7 @@ private:
|
|||
/// Annotation was successful.
|
||||
ANK_Success
|
||||
};
|
||||
AnnotatedNameKind TryAnnotateName(bool IsAddressOfOperand,
|
||||
CorrectionCandidateCallback *CCC = nullptr);
|
||||
AnnotatedNameKind TryAnnotateName(CorrectionCandidateCallback *CCC = nullptr);
|
||||
|
||||
/// Push a tok::annot_cxxscope token onto the token stream.
|
||||
void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
|
||||
|
|
|
@ -1855,29 +1855,52 @@ public:
|
|||
/// Describes the result of the name lookup and resolution performed
|
||||
/// by \c ClassifyName().
|
||||
enum NameClassificationKind {
|
||||
/// This name is not a type or template in this context, but might be
|
||||
/// something else.
|
||||
NC_Unknown,
|
||||
/// Classification failed; an error has been produced.
|
||||
NC_Error,
|
||||
/// The name has been typo-corrected to a keyword.
|
||||
NC_Keyword,
|
||||
/// The name was classified as a type.
|
||||
NC_Type,
|
||||
NC_Expression,
|
||||
NC_NestedNameSpecifier,
|
||||
/// The name was classified as a specific non-type, non-template
|
||||
/// 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,
|
||||
/// The name was classified as a variable template name.
|
||||
NC_VarTemplate,
|
||||
/// The name was classified as a function template name.
|
||||
NC_FunctionTemplate,
|
||||
/// The name was classified as an ADL-only function template name.
|
||||
NC_UndeclaredTemplate,
|
||||
};
|
||||
|
||||
class NameClassification {
|
||||
NameClassificationKind Kind;
|
||||
ExprResult Expr;
|
||||
TemplateName Template;
|
||||
ParsedType Type;
|
||||
union {
|
||||
ExprResult Expr;
|
||||
NamedDecl *NonTypeDecl;
|
||||
TemplateName Template;
|
||||
ParsedType Type;
|
||||
};
|
||||
|
||||
explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
|
||||
|
||||
public:
|
||||
NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {}
|
||||
|
||||
NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
|
||||
|
||||
NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {}
|
||||
|
@ -1890,8 +1913,24 @@ public:
|
|||
return NameClassification(NC_Unknown);
|
||||
}
|
||||
|
||||
static NameClassification NestedNameSpecifier() {
|
||||
return NameClassification(NC_NestedNameSpecifier);
|
||||
static NameClassification ContextIndependentExpr(ExprResult E) {
|
||||
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) {
|
||||
|
@ -1920,14 +1959,19 @@ public:
|
|||
|
||||
NameClassificationKind getKind() const { return Kind; }
|
||||
|
||||
ExprResult getExpression() const {
|
||||
assert(Kind == NC_ContextIndependentExpr);
|
||||
return Expr;
|
||||
}
|
||||
|
||||
ParsedType getType() const {
|
||||
assert(Kind == NC_Type);
|
||||
return Type;
|
||||
}
|
||||
|
||||
ExprResult getExpression() const {
|
||||
assert(Kind == NC_Expression);
|
||||
return Expr;
|
||||
NamedDecl *getNonTypeDecl() const {
|
||||
assert(Kind == NC_NonType);
|
||||
return NonTypeDecl;
|
||||
}
|
||||
|
||||
TemplateName getTemplateName() const {
|
||||
|
@ -1971,17 +2015,29 @@ public:
|
|||
/// \param NextToken The token following the identifier. Used to help
|
||||
/// 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.
|
||||
NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS,
|
||||
IdentifierInfo *&Name, SourceLocation NameLoc,
|
||||
const Token &NextToken,
|
||||
bool IsAddressOfOperand,
|
||||
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.
|
||||
enum class TemplateNameKindForDiagnostics {
|
||||
ClassTemplate,
|
||||
|
@ -3407,6 +3463,7 @@ public:
|
|||
LookupNameKind NameKind,
|
||||
RedeclarationKind Redecl
|
||||
= NotForRedeclaration);
|
||||
bool LookupBuiltin(LookupResult &R);
|
||||
bool LookupName(LookupResult &R, Scope *S,
|
||||
bool AllowBuiltinCreation = false);
|
||||
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
|
||||
|
@ -4389,6 +4446,10 @@ public:
|
|||
TemplateArgumentListInfo *ExplicitTemplateArgs = 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,
|
||||
IdentifierInfo *II,
|
||||
bool AllowBuiltinCreation=false);
|
||||
|
|
|
@ -2929,28 +2929,29 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
|
|||
IdentifierInfo *Name = AfterScope.getIdentifierInfo();
|
||||
Sema::NameClassification Classification = Actions.ClassifyName(
|
||||
getCurScope(), SS, Name, AfterScope.getLocation(), Next,
|
||||
/*IsAddressOfOperand=*/false, /*CCC=*/nullptr);
|
||||
/*CCC=*/nullptr);
|
||||
switch (Classification.getKind()) {
|
||||
case Sema::NC_Error:
|
||||
SkipMalformedDecl();
|
||||
return true;
|
||||
|
||||
case Sema::NC_Keyword:
|
||||
case Sema::NC_NestedNameSpecifier:
|
||||
llvm_unreachable("typo correction and nested name specifiers not "
|
||||
"possible here");
|
||||
llvm_unreachable("typo correction is not possible here");
|
||||
|
||||
case Sema::NC_Type:
|
||||
case Sema::NC_TypeTemplate:
|
||||
case Sema::NC_UndeclaredNonType:
|
||||
case Sema::NC_UndeclaredTemplate:
|
||||
// Not a previously-declared non-type entity.
|
||||
MightBeDeclarator = false;
|
||||
break;
|
||||
|
||||
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_FunctionTemplate:
|
||||
case Sema::NC_UndeclaredTemplate:
|
||||
// Might be a redeclaration of a prior entity.
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -840,13 +840,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
|
||||
|
||||
case tok::annot_primary_expr:
|
||||
assert(Res.get() == nullptr && "Stray primary-expression annotation?");
|
||||
Res = getExprAnnotation(Tok);
|
||||
ConsumeAnnotationToken();
|
||||
if (!Res.isInvalid() && Tok.is(tok::less))
|
||||
checkPotentialAngleBracket(Res);
|
||||
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_decltype:
|
||||
// Annotate the token and tail recurse.
|
||||
|
|
|
@ -555,27 +555,66 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
return false;
|
||||
}
|
||||
|
||||
ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
|
||||
ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand,
|
||||
Token &Replacement) {
|
||||
SourceLocation TemplateKWLoc;
|
||||
UnqualifiedId Name;
|
||||
if (ParseUnqualifiedId(SS,
|
||||
/*EnteringContext=*/false,
|
||||
/*AllowDestructorName=*/false,
|
||||
/*AllowConstructorName=*/false,
|
||||
/*AllowDeductionGuide=*/false,
|
||||
/*ObjectType=*/nullptr, &TemplateKWLoc, Name))
|
||||
return ExprError();
|
||||
ExprResult E;
|
||||
|
||||
// This is only the direct operand of an & operator if it is not
|
||||
// followed by a postfix-expression suffix.
|
||||
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
|
||||
isAddressOfOperand = false;
|
||||
// We may have already annotated this id-expression.
|
||||
switch (Tok.getKind()) {
|
||||
case tok::annot_non_type: {
|
||||
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))
|
||||
checkPotentialAngleBracket(E);
|
||||
return E;
|
||||
|
|
|
@ -187,7 +187,7 @@ Retry:
|
|||
// Try to limit which sets of keywords should be included in typo
|
||||
// correction based on what the next token is.
|
||||
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
|
||||
// eat the semicolon if that's what stopped us.
|
||||
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
|
||||
// to types and identifiers, in order to try to recover from errors.
|
||||
TentativeParseCCC CCC(Next);
|
||||
switch (TryAnnotateName(false /* no nested name specifier */, &CCC)) {
|
||||
switch (TryAnnotateName(&CCC)) {
|
||||
case ANK_Error:
|
||||
return TPResult::Error;
|
||||
case ANK_TentativeDecl:
|
||||
|
@ -1569,7 +1569,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
|||
} else {
|
||||
// Try to resolve the name. If it doesn't exist, assume it was
|
||||
// intended to name a type and keep disambiguating.
|
||||
switch (TryAnnotateName(false /* SS is not dependent */)) {
|
||||
switch (TryAnnotateName()) {
|
||||
case ANK_Error:
|
||||
return TPResult::Error;
|
||||
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
|
||||
/// 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,
|
||||
/// no typo correction will be performed.
|
||||
Parser::AnnotatedNameKind
|
||||
Parser::TryAnnotateName(bool IsAddressOfOperand,
|
||||
CorrectionCandidateCallback *CCC) {
|
||||
Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
|
||||
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
|
||||
|
||||
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
|
||||
// there (eg, after correcting 'A::template B<X>::C' [sic], we would need to
|
||||
// jump back into scope specifier parsing).
|
||||
Sema::NameClassification Classification =
|
||||
Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
|
||||
IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
|
||||
Sema::NameClassification Classification = Actions.ClassifyName(
|
||||
getCurScope(), SS, Name, NameLoc, Next, SS.isEmpty() ? CCC : nullptr);
|
||||
|
||||
// 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
|
||||
|
@ -1618,7 +1614,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
|||
FakeNext.setKind(tok::unknown);
|
||||
Classification =
|
||||
Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, FakeNext,
|
||||
IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
|
||||
SS.isEmpty() ? CCC : nullptr);
|
||||
}
|
||||
|
||||
switch (Classification.getKind()) {
|
||||
|
@ -1671,7 +1667,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
|||
return ANK_Success;
|
||||
}
|
||||
|
||||
case Sema::NC_Expression:
|
||||
case Sema::NC_ContextIndependentExpr:
|
||||
Tok.setKind(tok::annot_primary_expr);
|
||||
setExprAnnotation(Tok, Classification.getExpression());
|
||||
Tok.setAnnotationEndLoc(NameLoc);
|
||||
|
@ -1680,6 +1676,29 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
|||
PP.AnnotateCachedTokens(Tok);
|
||||
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:
|
||||
if (Next.isNot(tok::less)) {
|
||||
// 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_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.
|
||||
|
|
|
@ -845,18 +845,18 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
|
|||
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
|
||||
}
|
||||
|
||||
Sema::NameClassification
|
||||
Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
|
||||
SourceLocation NameLoc, const Token &NextToken,
|
||||
bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) {
|
||||
Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
|
||||
IdentifierInfo *&Name,
|
||||
SourceLocation NameLoc,
|
||||
const Token &NextToken,
|
||||
CorrectionCandidateCallback *CCC) {
|
||||
DeclarationNameInfo NameInfo(Name, NameLoc);
|
||||
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
||||
|
||||
if (NextToken.is(tok::coloncolon)) {
|
||||
NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation());
|
||||
BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false);
|
||||
} else if (getLangOpts().CPlusPlus && SS.isSet() &&
|
||||
isCurrentClassName(*Name, S, &SS)) {
|
||||
assert(NextToken.isNot(tok::coloncolon) &&
|
||||
"parse nested name specifiers before calling ClassifyName");
|
||||
if (getLangOpts().CPlusPlus && SS.isSet() &&
|
||||
isCurrentClassName(*Name, S, &SS)) {
|
||||
// Per [class.qual]p2, this names the constructors of SS, not the
|
||||
// injected-class-name. We don't have a classification for that.
|
||||
// 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
|
||||
// unqualified lookup mechanism.
|
||||
if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
|
||||
ExprResult E = LookupInObjCMethod(Result, S, Name, true);
|
||||
if (E.get() || E.isInvalid())
|
||||
return E;
|
||||
DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name);
|
||||
if (Ivar.isInvalid())
|
||||
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;
|
||||
|
@ -897,7 +903,7 @@ Corrected:
|
|||
// In C++, this is an ADL-only call.
|
||||
// FIXME: Reference?
|
||||
if (getLangOpts().CPlusPlus)
|
||||
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
|
||||
return NameClassification::UndeclaredNonType();
|
||||
|
||||
// C90 6.3.2.2:
|
||||
// If the expression that precedes the parenthesized argument list in a
|
||||
|
@ -911,11 +917,8 @@ Corrected:
|
|||
// appeared.
|
||||
//
|
||||
// We also allow this in C99 as an extension.
|
||||
if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
|
||||
Result.addDecl(D);
|
||||
Result.resolveKind();
|
||||
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
|
||||
}
|
||||
if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S))
|
||||
return NameClassification::NonType(D);
|
||||
}
|
||||
|
||||
if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
|
||||
|
@ -990,9 +993,12 @@ Corrected:
|
|||
// reference the ivar.
|
||||
// FIXME: This is a gross hack.
|
||||
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
|
||||
Result.clear();
|
||||
ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
|
||||
return E;
|
||||
DeclResult R =
|
||||
LookupIvarInObjCMethod(Result, S, Ivar->getIdentifier());
|
||||
if (R.isInvalid())
|
||||
return NameClassification::Error();
|
||||
if (R.isUsable())
|
||||
return NameClassification::NonType(Ivar);
|
||||
}
|
||||
|
||||
goto Corrected;
|
||||
|
@ -1018,9 +1024,7 @@ Corrected:
|
|||
// perform some heroics to see if we actually have a
|
||||
// template-argument-list, which would indicate a missing 'template'
|
||||
// keyword here.
|
||||
return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
|
||||
NameInfo, IsAddressOfOperand,
|
||||
/*TemplateArgs=*/nullptr);
|
||||
return NameClassification::DependentNonType();
|
||||
}
|
||||
|
||||
case LookupResult::Found:
|
||||
|
@ -1167,9 +1171,57 @@ Corrected:
|
|||
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())
|
||||
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
|
||||
nullptr, S);
|
||||
return NameClassification::ContextIndependentExpr(
|
||||
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));
|
||||
return BuildDeclarationNameExpr(SS, Result, ADL);
|
||||
|
|
|
@ -2482,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
|
|||
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
|
||||
}
|
||||
|
||||
/// LookupInObjCMethod - The parser has read a name in, and Sema has
|
||||
/// detected that we're currently inside an ObjC method. Perform some
|
||||
/// additional lookup.
|
||||
/// 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.
|
||||
///
|
||||
/// Ideally, most of this would be done by lookup, but there's
|
||||
/// actually quite a lot of extra work involved.
|
||||
///
|
||||
/// Returns a null sentinel to indicate trivial success.
|
||||
ExprResult
|
||||
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||
IdentifierInfo *II, bool AllowBuiltinCreation) {
|
||||
DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
|
||||
IdentifierInfo *II) {
|
||||
SourceLocation Loc = Lookup.getNameLoc();
|
||||
ObjCMethodDecl *CurMethod = getCurMethodDecl();
|
||||
|
||||
// Check for error condition which is already reported.
|
||||
if (!CurMethod)
|
||||
return ExprError();
|
||||
return DeclResult(true);
|
||||
|
||||
// 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
|
||||
|
@ -2526,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
|||
ObjCIvarDecl *IV = nullptr;
|
||||
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
|
||||
// Diagnose using an ivar in a class method.
|
||||
if (IsClassMethod)
|
||||
return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
|
||||
<< IV->getDeclName());
|
||||
|
||||
// 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();
|
||||
if (IsClassMethod) {
|
||||
Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
|
||||
return DeclResult(true);
|
||||
}
|
||||
|
||||
// Diagnose the use of an ivar outside of the declaring class.
|
||||
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
|
||||
|
@ -2545,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
|||
!getLangOpts().DebuggerSupport)
|
||||
Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName();
|
||||
|
||||
// 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;
|
||||
// Success.
|
||||
return IV;
|
||||
}
|
||||
} else if (CurMethod->isInstanceMethod()) {
|
||||
// We should warn if a local variable hides an ivar.
|
||||
|
@ -2599,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
|
|||
} else if (Lookup.isSingleResult() &&
|
||||
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
|
||||
// If accessing a stand-alone ivar in a class method, this is an error.
|
||||
if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl()))
|
||||
return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
|
||||
<< IV->getDeclName());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (const ObjCIvarDecl *IV =
|
||||
dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) {
|
||||
Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
|
||||
return DeclResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
return ExprResult((Expr *)nullptr);
|
||||
return ExprResult(false);
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// fail.
|
||||
static bool LookupBuiltin(Sema &S, LookupResult &R) {
|
||||
bool Sema::LookupBuiltin(LookupResult &R) {
|
||||
Sema::LookupNameKind NameKind = R.getLookupKind();
|
||||
|
||||
// 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) {
|
||||
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
|
||||
if (II) {
|
||||
if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
|
||||
if (II == S.getASTContext().getMakeIntegerSeqName()) {
|
||||
R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
|
||||
if (getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
|
||||
if (II == getASTContext().getMakeIntegerSeqName()) {
|
||||
R.addDecl(getASTContext().getMakeIntegerSeqDecl());
|
||||
return true;
|
||||
} else if (II == S.getASTContext().getTypePackElementName()) {
|
||||
R.addDecl(S.getASTContext().getTypePackElementDecl());
|
||||
} else if (II == getASTContext().getTypePackElementName()) {
|
||||
R.addDecl(getASTContext().getTypePackElementDecl());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
if (Index.first) {
|
||||
InsertOCLBuiltinDeclarationsFromTable(S, R, II, Index.first - 1,
|
||||
InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1,
|
||||
Index.second);
|
||||
return true;
|
||||
}
|
||||
|
@ -860,14 +860,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
|
|||
if (unsigned BuiltinID = II->getBuiltinID()) {
|
||||
// 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.
|
||||
if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) &&
|
||||
S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
|
||||
if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
|
||||
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
|
||||
return false;
|
||||
|
||||
if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II,
|
||||
BuiltinID, S.TUScope,
|
||||
R.isForRedeclaration(),
|
||||
R.getNameLoc())) {
|
||||
if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II,
|
||||
BuiltinID, TUScope,
|
||||
R.isForRedeclaration(),
|
||||
R.getNameLoc())) {
|
||||
R.addDecl(D);
|
||||
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;
|
||||
|
||||
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
|
||||
// corresponds to a compiler builtin, create the decl object for the builtin
|
||||
// now, injecting it into translation unit scope, and return it.
|
||||
if (AllowBuiltinCreation && LookupBuiltin(*this, R))
|
||||
if (AllowBuiltinCreation && LookupBuiltin(R))
|
||||
return true;
|
||||
|
||||
// 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]{};
|
||||
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