r374826 - PR43080: Do not build context-sensitive expressions during name classification.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 14 14:53:03 PDT 2019
Author: rsmith
Date: Mon Oct 14 14:53:03 2019
New Revision: 374826
URL: http://llvm.org/viewvc/llvm-project?rev=374826&view=rev
Log:
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
Added:
cfe/trunk/test/CodeGenCXX/odr-use-lookahead.cpp
Modified:
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/test/SemaCXX/lambda-invalid-capture.cpp
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Mon Oct 14 14:53:03 2019
@@ -728,6 +728,11 @@ ANNOTATION(typename) // annotation f
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())"
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Oct 14 14:53:03 2019
@@ -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);
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Oct 14 14:53:03 2019
@@ -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);
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Oct 14 14:53:03 2019
@@ -2929,28 +2929,29 @@ Parser::DiagnoseMissingSemiAfterTagDefin
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;
}
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Mon Oct 14 14:53:03 2019
@@ -840,13 +840,23 @@ ExprResult Parser::ParseCastExpression(b
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.
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Oct 14 14:53:03 2019
@@ -555,27 +555,66 @@ bool Parser::ParseOptionalCXXScopeSpecif
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();
-
- // This is only the direct operand of an & operator if it is not
- // followed by a postfix-expression suffix.
- if (isAddressOfOperand && isPostfixExpressionSuffixStart())
- isAddressOfOperand = false;
-
- ExprResult E = Actions.ActOnIdExpression(
- getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
- isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false,
- &Replacement);
+ ExprResult E;
+
+ // 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;
+ }
+
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
checkPotentialAngleBracket(E);
return E;
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Mon Oct 14 14:53:03 2019
@@ -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);
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Oct 14 14:53:03 2019
@@ -1330,7 +1330,7 @@ Parser::isCXXDeclarationSpecifier(Parser
// 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
} 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:
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Oct 14 14:53:03 2019
@@ -1561,13 +1561,10 @@ void Parser::AnnotateScopeToken(CXXScope
/// 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 IsAddressOf
// 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 IsAddressOf
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 IsAddressOf
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 IsAddressOf
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 IsAddressOf
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.
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Oct 14 14:53:03 2019
@@ -845,18 +845,18 @@ static ParsedType buildNestedType(Sema &
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, CXXScopeSpe
// 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);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Oct 14 14:53:03 2019
@@ -2482,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarati
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 &L
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 &L
!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 &L
} 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 (const ObjCIvarDecl *IV =
+ dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) {
+ 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.
- return ExprResult((Expr *)nullptr);
+ return ExprResult(false);
}
/// Cast a base object to a member's actual type.
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Oct 14 14:53:03 2019
@@ -826,7 +826,7 @@ static void InsertOCLBuiltinDeclarations
/// 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, Looku
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, Looku
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, Lookup
}
}
- 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, S
// 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
Added: cfe/trunk/test/CodeGenCXX/odr-use-lookahead.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/odr-use-lookahead.cpp?rev=374826&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/odr-use-lookahead.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/odr-use-lookahead.cpp Mon Oct 14 14:53:03 2019
@@ -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; }
+}
Modified: cfe/trunk/test/SemaCXX/lambda-invalid-capture.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-invalid-capture.cpp?rev=374826&r1=374825&r2=374826&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-invalid-capture.cpp (original)
+++ cfe/trunk/test/SemaCXX/lambda-invalid-capture.cpp Mon Oct 14 14:53:03 2019
@@ -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}}
+ }();
+}
More information about the cfe-commits
mailing list