Remove delayed typo expressions (#143423)
This removes the delayed typo correction functionality from Clang (regular typo correction still remains) due to fragility of the solution. An RFC was posted here: https://discourse.llvm.org/t/rfc-removing-support-for-delayed-typo-correction/86631 and while that RFC was asking for folks to consider stepping up to be maintainers, and we did have a few new contributors show some interest, experiments show that it's likely worth it to remove this functionality entirely and focus efforts on improving regular typo correction. This removal fixes ~20 open issues (quite possibly more), improves compile time performance by roughly .3-.4% (https://llvm-compile-time-tracker.com/?config=Overview&stat=instructions%3Au&remote=AaronBallman&sortBy=date), and does not appear to regress diagnostic behavior in a way we wouldn't find acceptable. Fixes #142457 Fixes #139913 Fixes #138850 Fixes #137867 Fixes #137860 Fixes #107840 Fixes #93308 Fixes #69470 Fixes #59391 Fixes #58172 Fixes #46215 Fixes #45915 Fixes #45891 Fixes #44490 Fixes #36703 Fixes #32903 Fixes #23312 Fixes #69874
This commit is contained in:
parent
541e5118ce
commit
9eef4d1c5f
@ -974,7 +974,7 @@ class Foo final {})cpp";
|
||||
HI.Name = "abc";
|
||||
HI.Kind = index::SymbolKind::Variable;
|
||||
HI.NamespaceScope = "";
|
||||
HI.Definition = "int abc = <recovery - expr>()";
|
||||
HI.Definition = "int abc";
|
||||
HI.Type = "int";
|
||||
HI.AccessSpecifier = "public";
|
||||
}},
|
||||
|
||||
@ -622,6 +622,14 @@ Improvements to Clang's diagnostics
|
||||
|
||||
- Improved the FixIts for unused lambda captures.
|
||||
|
||||
- Delayed typo correction was removed from the compiler; immediate typo
|
||||
correction behavior remains the same. Delayed typo correction facilities were
|
||||
fragile and unmaintained, and the removal closed the following issues:
|
||||
#GH142457, #GH139913, #GH138850, #GH137867, #GH137860, #GH107840, #GH93308,
|
||||
#GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
|
||||
#GH36703, #GH32903, #GH23312, #GH69874.
|
||||
|
||||
|
||||
Improvements to Clang's time-trace
|
||||
----------------------------------
|
||||
|
||||
|
||||
@ -240,8 +240,7 @@ public:
|
||||
return static_cast<bool>(getDependence() & ExprDependence::UnexpandedPack);
|
||||
}
|
||||
|
||||
/// Whether this expression contains subexpressions which had errors, e.g. a
|
||||
/// TypoExpr.
|
||||
/// Whether this expression contains subexpressions which had errors.
|
||||
bool containsErrors() const {
|
||||
return static_cast<bool>(getDependence() & ExprDependence::Error);
|
||||
}
|
||||
@ -6965,36 +6964,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// TypoExpr - Internal placeholder for expressions where typo correction
|
||||
/// still needs to be performed and/or an error diagnostic emitted.
|
||||
class TypoExpr : public Expr {
|
||||
// The location for the typo name.
|
||||
SourceLocation TypoLoc;
|
||||
|
||||
public:
|
||||
TypoExpr(QualType T, SourceLocation TypoLoc)
|
||||
: Expr(TypoExprClass, T, VK_LValue, OK_Ordinary), TypoLoc(TypoLoc) {
|
||||
assert(T->isDependentType() && "TypoExpr given a non-dependent type");
|
||||
setDependence(ExprDependence::TypeValueInstantiation |
|
||||
ExprDependence::Error);
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY { return TypoLoc; }
|
||||
SourceLocation getEndLoc() const LLVM_READONLY { return TypoLoc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == TypoExprClass;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// This class represents BOTH the OpenMP Array Section and OpenACC 'subarray',
|
||||
/// with a boolean differentiator.
|
||||
/// OpenMP 5.0 [2.1.5, Array Sections].
|
||||
|
||||
@ -2956,7 +2956,6 @@ DEF_TRAVERSE_STMT(CXXRewrittenBinaryOperator, {
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
|
||||
DEF_TRAVERSE_STMT(TypoExpr, {})
|
||||
DEF_TRAVERSE_STMT(RecoveryExpr, {})
|
||||
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
|
||||
|
||||
|
||||
@ -202,7 +202,6 @@ def ShuffleVectorExpr : StmtNode<Expr>;
|
||||
def ConvertVectorExpr : StmtNode<Expr>;
|
||||
def BlockExpr : StmtNode<Expr>;
|
||||
def OpaqueValueExpr : StmtNode<Expr>;
|
||||
def TypoExpr : StmtNode<Expr>;
|
||||
def RecoveryExpr : StmtNode<Expr>;
|
||||
def BuiltinBitCastExpr : StmtNode<ExplicitCastExpr>;
|
||||
def EmbedExpr : StmtNode<Expr>;
|
||||
|
||||
@ -4169,8 +4169,7 @@ private:
|
||||
bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
|
||||
llvm::function_ref<void()> ExpressionStarts =
|
||||
llvm::function_ref<void()>(),
|
||||
bool FailImmediatelyOnInvalidExpr = false,
|
||||
bool EarlyTypoCorrection = false);
|
||||
bool FailImmediatelyOnInvalidExpr = false);
|
||||
|
||||
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
|
||||
/// used for misc language extensions.
|
||||
|
||||
@ -6713,10 +6713,6 @@ public:
|
||||
/// this expression evaluation context.
|
||||
unsigned NumCleanupObjects;
|
||||
|
||||
/// The number of typos encountered during this expression evaluation
|
||||
/// context (i.e. the number of TypoExprs created).
|
||||
unsigned NumTypos;
|
||||
|
||||
MaybeODRUseExprSet SavedMaybeODRUseExprs;
|
||||
|
||||
/// The lambdas that are present within this context, if it
|
||||
@ -6813,7 +6809,7 @@ public:
|
||||
Decl *ManglingContextDecl,
|
||||
ExpressionKind ExprContext)
|
||||
: Context(Context), ParentCleanup(ParentCleanup),
|
||||
NumCleanupObjects(NumCleanupObjects), NumTypos(0),
|
||||
NumCleanupObjects(NumCleanupObjects),
|
||||
ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext),
|
||||
InDiscardedStatement(false), InImmediateFunctionContext(false),
|
||||
InImmediateEscalatingFunctionContext(false) {}
|
||||
@ -7146,8 +7142,7 @@ public:
|
||||
CorrectionCandidateCallback &CCC,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
|
||||
ArrayRef<Expr *> Args = {},
|
||||
DeclContext *LookupCtx = nullptr,
|
||||
TypoExpr **Out = nullptr);
|
||||
DeclContext *LookupCtx = nullptr);
|
||||
|
||||
/// If \p D cannot be odr-used in the current expression evaluation context,
|
||||
/// return a reason explaining why. Otherwise, return NOUR_None.
|
||||
@ -8748,40 +8743,6 @@ public:
|
||||
|
||||
ExprResult CheckUnevaluatedOperand(Expr *E);
|
||||
|
||||
/// Process any TypoExprs in the given Expr and its children,
|
||||
/// generating diagnostics as appropriate and returning a new Expr if there
|
||||
/// were typos that were all successfully corrected and ExprError if one or
|
||||
/// more typos could not be corrected.
|
||||
///
|
||||
/// \param E The Expr to check for TypoExprs.
|
||||
///
|
||||
/// \param InitDecl A VarDecl to avoid because the Expr being corrected is its
|
||||
/// initializer.
|
||||
///
|
||||
/// \param RecoverUncorrectedTypos If true, when typo correction fails, it
|
||||
/// will rebuild the given Expr with all TypoExprs degraded to RecoveryExprs.
|
||||
///
|
||||
/// \param Filter A function applied to a newly rebuilt Expr to determine if
|
||||
/// it is an acceptable/usable result from a single combination of typo
|
||||
/// corrections. As long as the filter returns ExprError, different
|
||||
/// combinations of corrections will be tried until all are exhausted.
|
||||
ExprResult CorrectDelayedTyposInExpr(
|
||||
Expr *E, VarDecl *InitDecl = nullptr,
|
||||
bool RecoverUncorrectedTypos = false,
|
||||
llvm::function_ref<ExprResult(Expr *)> Filter =
|
||||
[](Expr *E) -> ExprResult { return E; });
|
||||
|
||||
ExprResult CorrectDelayedTyposInExpr(
|
||||
ExprResult ER, VarDecl *InitDecl = nullptr,
|
||||
bool RecoverUncorrectedTypos = false,
|
||||
llvm::function_ref<ExprResult(Expr *)> Filter =
|
||||
[](Expr *E) -> ExprResult { return E; }) {
|
||||
return ER.isInvalid()
|
||||
? ER
|
||||
: CorrectDelayedTyposInExpr(ER.get(), InitDecl,
|
||||
RecoverUncorrectedTypos, Filter);
|
||||
}
|
||||
|
||||
IfExistsResult
|
||||
CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS,
|
||||
const DeclarationNameInfo &TargetNameInfo);
|
||||
@ -9283,12 +9244,6 @@ public:
|
||||
/// for C++ records.
|
||||
llvm::FoldingSet<SpecialMemberOverloadResultEntry> SpecialMemberCache;
|
||||
|
||||
/// Holds TypoExprs that are created from `createDelayedTypo`. This is used by
|
||||
/// `TransformTypos` in order to keep track of any TypoExprs that are created
|
||||
/// recursively during typo correction and wipe them away if the correction
|
||||
/// fails.
|
||||
llvm::SmallVector<TypoExpr *, 2> TypoExprs;
|
||||
|
||||
enum class AcceptableKind { Visible, Reachable };
|
||||
|
||||
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
|
||||
@ -9376,10 +9331,6 @@ public:
|
||||
bool VolatileArg, bool RValueThis, bool ConstThis,
|
||||
bool VolatileThis);
|
||||
|
||||
typedef std::function<void(const TypoCorrection &)> TypoDiagnosticGenerator;
|
||||
typedef std::function<ExprResult(Sema &, TypoExpr *, TypoCorrection)>
|
||||
TypoRecoveryCallback;
|
||||
|
||||
RedeclarationKind forRedeclarationInCurContext() const;
|
||||
|
||||
/// Look up a name, looking for a single declaration. Return
|
||||
@ -9733,51 +9684,6 @@ public:
|
||||
const ObjCObjectPointerType *OPT = nullptr,
|
||||
bool RecordFailure = true);
|
||||
|
||||
/// Try to "correct" a typo in the source code by finding
|
||||
/// visible declarations whose names are similar to the name that was
|
||||
/// present in the source code.
|
||||
///
|
||||
/// \param TypoName the \c DeclarationNameInfo structure that contains
|
||||
/// the name that was present in the source code along with its location.
|
||||
///
|
||||
/// \param LookupKind the name-lookup criteria used to search for the name.
|
||||
///
|
||||
/// \param S the scope in which name lookup occurs.
|
||||
///
|
||||
/// \param SS the nested-name-specifier that precedes the name we're
|
||||
/// looking for, if present.
|
||||
///
|
||||
/// \param CCC A CorrectionCandidateCallback object that provides further
|
||||
/// validation of typo correction candidates. It also provides flags for
|
||||
/// determining the set of keywords permitted.
|
||||
///
|
||||
/// \param TDG A TypoDiagnosticGenerator functor that will be used to print
|
||||
/// diagnostics when the actual typo correction is attempted.
|
||||
///
|
||||
/// \param TRC A TypoRecoveryCallback functor that will be used to build an
|
||||
/// Expr from a typo correction candidate.
|
||||
///
|
||||
/// \param MemberContext if non-NULL, the context in which to look for
|
||||
/// a member access expression.
|
||||
///
|
||||
/// \param EnteringContext whether we're entering the context described by
|
||||
/// the nested-name-specifier SS.
|
||||
///
|
||||
/// \param OPT when non-NULL, the search for visible declarations will
|
||||
/// also walk the protocols in the qualified interfaces of \p OPT.
|
||||
///
|
||||
/// \returns a new \c TypoExpr that will later be replaced in the AST with an
|
||||
/// Expr representing the result of performing typo correction, or nullptr if
|
||||
/// typo correction is not possible. If nullptr is returned, no diagnostics
|
||||
/// will be emitted and it is the responsibility of the caller to emit any
|
||||
/// that are needed.
|
||||
TypoExpr *CorrectTypoDelayed(
|
||||
const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind,
|
||||
Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC,
|
||||
TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC,
|
||||
CorrectTypoKind Mode, DeclContext *MemberContext = nullptr,
|
||||
bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr);
|
||||
|
||||
/// Kinds of missing import. Note, the values of these enumerators correspond
|
||||
/// to %select values in diagnostics.
|
||||
enum class MissingImportKind {
|
||||
@ -9796,20 +9702,6 @@ public:
|
||||
SourceLocation DeclLoc, ArrayRef<Module *> Modules,
|
||||
MissingImportKind MIK, bool Recover);
|
||||
|
||||
struct TypoExprState {
|
||||
std::unique_ptr<TypoCorrectionConsumer> Consumer;
|
||||
TypoDiagnosticGenerator DiagHandler;
|
||||
TypoRecoveryCallback RecoveryHandler;
|
||||
TypoExprState();
|
||||
TypoExprState(TypoExprState &&other) noexcept;
|
||||
TypoExprState &operator=(TypoExprState &&other) noexcept;
|
||||
};
|
||||
|
||||
const TypoExprState &getTypoExprState(TypoExpr *TE) const;
|
||||
|
||||
/// Clears the state of the given TypoExpr.
|
||||
void clearDelayedTypo(TypoExpr *TE);
|
||||
|
||||
/// Called on #pragma clang __debug dump II
|
||||
void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II);
|
||||
|
||||
@ -9832,23 +9724,15 @@ private:
|
||||
/// Determine if we could use all the declarations in the module.
|
||||
bool isUsableModule(const Module *M);
|
||||
|
||||
/// Helper for CorrectTypo and CorrectTypoDelayed used to create and
|
||||
/// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction
|
||||
/// should be skipped entirely.
|
||||
/// Helper for CorrectTypo used to create and populate a new
|
||||
/// TypoCorrectionConsumer. Returns nullptr if typo correction should be
|
||||
/// skipped entirely.
|
||||
std::unique_ptr<TypoCorrectionConsumer> makeTypoCorrectionConsumer(
|
||||
const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind,
|
||||
Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC,
|
||||
DeclContext *MemberContext, bool EnteringContext,
|
||||
const ObjCObjectPointerType *OPT, bool ErrorRecovery);
|
||||
|
||||
/// The set of unhandled TypoExprs and their associated state.
|
||||
llvm::MapVector<TypoExpr *, TypoExprState> DelayedTypos;
|
||||
|
||||
/// Creates a new TypoExpr AST node.
|
||||
TypoExpr *createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
|
||||
TypoDiagnosticGenerator TDG,
|
||||
TypoRecoveryCallback TRC, SourceLocation TypoLoc);
|
||||
|
||||
/// Cache for module units which is usable for current module.
|
||||
llvm::DenseSet<const Module *> UsableModuleUnitsCache;
|
||||
|
||||
|
||||
@ -314,20 +314,6 @@ private:
|
||||
bool SearchNamespaces;
|
||||
};
|
||||
|
||||
inline Sema::TypoExprState::TypoExprState() {}
|
||||
|
||||
inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
inline Sema::TypoExprState &Sema::TypoExprState::
|
||||
operator=(Sema::TypoExprState &&other) noexcept {
|
||||
Consumer = std::move(other.Consumer);
|
||||
DiagHandler = std::move(other.DiagHandler);
|
||||
RecoveryHandler = std::move(other.RecoveryHandler);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
@ -3611,7 +3611,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
case PackExpansionExprClass:
|
||||
case SubstNonTypeTemplateParmPackExprClass:
|
||||
case FunctionParmPackExprClass:
|
||||
case TypoExprClass:
|
||||
case RecoveryExprClass:
|
||||
case CXXFoldExprClass:
|
||||
// Make a conservative assumption for dependent nodes.
|
||||
|
||||
@ -129,7 +129,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
||||
// FIXME: Is this wise? Should they get their own kind?
|
||||
case Expr::UnresolvedLookupExprClass:
|
||||
case Expr::UnresolvedMemberExprClass:
|
||||
case Expr::TypoExprClass:
|
||||
case Expr::DependentCoawaitExprClass:
|
||||
case Expr::CXXDependentScopeMemberExprClass:
|
||||
case Expr::DependentScopeDeclRefExprClass:
|
||||
|
||||
@ -17327,7 +17327,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
|
||||
case Expr::CXXDeleteExprClass:
|
||||
case Expr::CXXPseudoDestructorExprClass:
|
||||
case Expr::UnresolvedLookupExprClass:
|
||||
case Expr::TypoExprClass:
|
||||
case Expr::RecoveryExprClass:
|
||||
case Expr::DependentScopeDeclRefExprClass:
|
||||
case Expr::CXXConstructExprClass:
|
||||
|
||||
@ -4994,7 +4994,6 @@ recurse:
|
||||
case Expr::ParenListExprClass:
|
||||
case Expr::MSPropertyRefExprClass:
|
||||
case Expr::MSPropertySubscriptExprClass:
|
||||
case Expr::TypoExprClass: // This should no longer exist in the AST by now.
|
||||
case Expr::RecoveryExprClass:
|
||||
case Expr::ArraySectionExprClass:
|
||||
case Expr::OMPArrayShapingExprClass:
|
||||
|
||||
@ -2914,11 +2914,6 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
|
||||
PrintExpr(Node->getSourceExpr());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitTypoExpr(TypoExpr *Node) {
|
||||
// TODO: Print something reasonable for a TypoExpr, if necessary.
|
||||
llvm_unreachable("Cannot print TypoExpr nodes");
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitRecoveryExpr(RecoveryExpr *Node) {
|
||||
OS << "<recovery-expr>(";
|
||||
const char *Sep = "";
|
||||
|
||||
@ -2361,10 +2361,6 @@ void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
|
||||
VisitExpr(E);
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitTypoExpr(const TypoExpr *E) {
|
||||
VisitExpr(E);
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) {
|
||||
VisitExpr(E);
|
||||
}
|
||||
|
||||
@ -422,7 +422,6 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
|
||||
DefArgResult = ParseBraceInitializer();
|
||||
} else
|
||||
DefArgResult = ParseAssignmentExpression();
|
||||
DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult, Param);
|
||||
if (DefArgResult.isInvalid()) {
|
||||
Actions.ActOnParamDefaultArgumentError(Param, EqualLoc,
|
||||
/*DefaultArg=*/nullptr);
|
||||
|
||||
@ -436,7 +436,6 @@ bool Parser::ParseAttributeArgumentList(
|
||||
} else {
|
||||
Expr = ParseAssignmentExpression();
|
||||
}
|
||||
Expr = Actions.CorrectDelayedTyposInExpr(Expr);
|
||||
|
||||
if (Tok.is(tok::ellipsis))
|
||||
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
|
||||
@ -472,15 +471,6 @@ bool Parser::ParseAttributeArgumentList(
|
||||
Arg++;
|
||||
}
|
||||
|
||||
if (SawError) {
|
||||
// Ensure typos get diagnosed when errors were encountered while parsing the
|
||||
// expression list.
|
||||
for (auto &E : Exprs) {
|
||||
ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
|
||||
if (Expr.isUsable())
|
||||
E = Expr.get();
|
||||
}
|
||||
}
|
||||
return SawError;
|
||||
}
|
||||
|
||||
@ -565,9 +555,7 @@ unsigned Parser::ParseAttributeArgsCommon(
|
||||
nullptr,
|
||||
Sema::ExpressionEvaluationContextRecord::EK_AttrArgument);
|
||||
|
||||
ExprResult ArgExpr(
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
|
||||
|
||||
ExprResult ArgExpr = ParseAssignmentExpression();
|
||||
if (ArgExpr.isInvalid()) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
return 0;
|
||||
@ -3212,9 +3200,7 @@ void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName,
|
||||
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr,
|
||||
ExpressionKind::EK_AttrArgument);
|
||||
|
||||
ExprResult ArgExpr(
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
|
||||
|
||||
ExprResult ArgExpr = ParseAssignmentExpression();
|
||||
if (ArgExpr.isInvalid()) {
|
||||
Parens.skipToEnd();
|
||||
return;
|
||||
@ -6890,8 +6876,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
||||
// void (f()) requires true;
|
||||
Diag(Tok, diag::err_requires_clause_inside_parens);
|
||||
ConsumeToken();
|
||||
ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true));
|
||||
ExprResult TrailingRequiresClause =
|
||||
ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true);
|
||||
if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() &&
|
||||
!D.hasTrailingRequiresClause())
|
||||
// We're already ill-formed if we got here but we'll accept it anyway.
|
||||
@ -7538,8 +7524,7 @@ void Parser::ParseParameterDeclarationClause(
|
||||
Diag(Tok,
|
||||
diag::err_requires_clause_on_declarator_not_declaring_a_function);
|
||||
ConsumeToken();
|
||||
Actions.CorrectDelayedTyposInExpr(
|
||||
ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true));
|
||||
ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true);
|
||||
}
|
||||
|
||||
// Remember this parsed parameter in ParamInfo.
|
||||
@ -7653,7 +7638,6 @@ void Parser::ParseParameterDeclarationClause(
|
||||
}
|
||||
DefArgResult = ParseAssignmentExpression();
|
||||
}
|
||||
DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
|
||||
if (DefArgResult.isInvalid()) {
|
||||
Actions.ActOnParamDefaultArgumentError(Param, EqualLoc,
|
||||
/*DefaultArg=*/nullptr);
|
||||
@ -7799,8 +7783,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
|
||||
} else {
|
||||
EnterExpressionEvaluationContext Unevaluated(
|
||||
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
||||
NumElements =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
NumElements = ParseAssignmentExpression();
|
||||
}
|
||||
} else {
|
||||
if (StaticLoc.isValid()) {
|
||||
@ -7937,8 +7920,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
|
||||
bool isCastExpr;
|
||||
ParsedType CastTy;
|
||||
SourceRange CastRange;
|
||||
ExprResult Operand = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange));
|
||||
ExprResult Operand =
|
||||
ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange);
|
||||
if (HasParens)
|
||||
DS.setTypeArgumentRange(CastRange);
|
||||
|
||||
|
||||
@ -1071,10 +1071,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
||||
EnterExpressionEvaluationContext Unevaluated(
|
||||
Actions, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
|
||||
Sema::ExpressionEvaluationContextRecord::EK_Decltype);
|
||||
Result = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseExpression(), /*InitDecl=*/nullptr,
|
||||
/*RecoverUncorrectedTypos=*/false,
|
||||
[](Expr *E) { return E->hasPlaceholderType() ? ExprError() : E; });
|
||||
Result = ParseExpression();
|
||||
if (Result.isInvalid()) {
|
||||
DS.SetTypeSpecError();
|
||||
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
|
||||
@ -4465,8 +4462,7 @@ bool Parser::ParseCXXAssumeAttributeArg(
|
||||
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
|
||||
TentativeParsingAction TPA(*this);
|
||||
ExprResult Res(
|
||||
Actions.CorrectDelayedTyposInExpr(ParseConditionalExpression()));
|
||||
ExprResult Res = ParseConditionalExpression();
|
||||
if (Res.isInvalid()) {
|
||||
TPA.Commit();
|
||||
SkipUntil(tok::r_paren, tok::r_square, StopAtSemi | StopBeforeMatch);
|
||||
|
||||
@ -183,7 +183,6 @@ ExprResult Parser::ParseConstraintExpression() {
|
||||
ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr));
|
||||
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
|
||||
if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) {
|
||||
Actions.CorrectDelayedTyposInExpr(Res);
|
||||
return ExprError();
|
||||
}
|
||||
return Res;
|
||||
@ -244,7 +243,6 @@ Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {
|
||||
// the rest of the addition expression). Try to parse the rest of it here.
|
||||
if (PossibleNonPrimary)
|
||||
E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr);
|
||||
Actions.CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
return E;
|
||||
@ -256,14 +254,11 @@ Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {
|
||||
SourceLocation LogicalAndLoc = ConsumeToken();
|
||||
ExprResult RHS = ParsePrimary();
|
||||
if (RHS.isInvalid()) {
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
return ExprError();
|
||||
}
|
||||
ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc,
|
||||
tok::ampamp, LHS.get(), RHS.get());
|
||||
if (!Op.isUsable()) {
|
||||
Actions.CorrectDelayedTyposInExpr(RHS);
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
return ExprError();
|
||||
}
|
||||
LHS = Op;
|
||||
@ -281,14 +276,11 @@ Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) {
|
||||
ExprResult RHS =
|
||||
ParseConstraintLogicalAndExpression(IsTrailingRequiresClause);
|
||||
if (!RHS.isUsable()) {
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
return ExprError();
|
||||
}
|
||||
ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc,
|
||||
tok::pipepipe, LHS.get(), RHS.get());
|
||||
if (!Op.isUsable()) {
|
||||
Actions.CorrectDelayedTyposInExpr(RHS);
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
return ExprError();
|
||||
}
|
||||
LHS = Op;
|
||||
@ -408,7 +400,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
|
||||
}
|
||||
|
||||
if (TernaryMiddle.isInvalid()) {
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
LHS = ExprError();
|
||||
TernaryMiddle = nullptr;
|
||||
}
|
||||
@ -466,11 +457,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
|
||||
RHS = ParseCastExpression(CastParseKind::AnyCastExpr);
|
||||
|
||||
if (RHS.isInvalid()) {
|
||||
// FIXME: Errors generated by the delayed typo correction should be
|
||||
// printed before errors from parsing the RHS, not after.
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
if (TernaryMiddle.isUsable())
|
||||
TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
|
||||
LHS = ExprError();
|
||||
}
|
||||
|
||||
@ -503,11 +489,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
|
||||
RHSIsInitList = false;
|
||||
|
||||
if (RHS.isInvalid()) {
|
||||
// FIXME: Errors generated by the delayed typo correction should be
|
||||
// printed before errors from ParseRHSOfBinaryExpression, not after.
|
||||
Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
if (TernaryMiddle.isUsable())
|
||||
TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
|
||||
LHS = ExprError();
|
||||
}
|
||||
|
||||
@ -571,17 +552,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
|
||||
|
||||
LHS = CondOp;
|
||||
}
|
||||
// In this case, ActOnBinOp or ActOnConditionalOp performed the
|
||||
// CorrectDelayedTyposInExpr check.
|
||||
if (!getLangOpts().CPlusPlus)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure potential typos aren't left undiagnosed.
|
||||
if (LHS.isInvalid()) {
|
||||
Actions.CorrectDelayedTyposInExpr(OrigLHS);
|
||||
Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
|
||||
Actions.CorrectDelayedTyposInExpr(RHS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1711,7 +1681,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
// Reject array indices starting with a lambda-expression. '[[' is
|
||||
// reserved for attributes.
|
||||
if (CheckProhibitedCXX11Attribute()) {
|
||||
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
return ExprError();
|
||||
}
|
||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||
@ -1737,8 +1706,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
} else {
|
||||
Idx = ParseExpression(); // May be a comma expression
|
||||
}
|
||||
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
Idx = Actions.CorrectDelayedTyposInExpr(Idx);
|
||||
if (Idx.isInvalid()) {
|
||||
HasError = true;
|
||||
} else {
|
||||
@ -1746,7 +1713,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
}
|
||||
} else if (Tok.isNot(tok::r_square)) {
|
||||
if (ParseExpressionList(ArgExprs)) {
|
||||
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
@ -1762,7 +1728,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
// Consume ':'
|
||||
ColonLocFirst = ConsumeToken();
|
||||
if (Tok.isNot(tok::r_square))
|
||||
Length = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
Length = ParseExpression();
|
||||
}
|
||||
} else if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
|
||||
ColonProtectionRAIIObject RAII(*this);
|
||||
@ -1773,7 +1739,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
(getLangOpts().OpenMP < 50 ||
|
||||
((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50)))) {
|
||||
Length = ParseExpression();
|
||||
Length = Actions.CorrectDelayedTyposInExpr(Length);
|
||||
}
|
||||
}
|
||||
if (getLangOpts().OpenMP >= 50 &&
|
||||
@ -1789,8 +1754,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
}
|
||||
|
||||
SourceLocation RLoc = Tok.getLocation();
|
||||
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
|
||||
if (!LHS.isInvalid() && !HasError && !Length.isInvalid() &&
|
||||
!Stride.isInvalid() && Tok.is(tok::r_square)) {
|
||||
if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
|
||||
@ -1838,7 +1801,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
SourceLocation OpenLoc = ConsumeToken();
|
||||
|
||||
if (ParseSimpleExpressionList(ExecConfigExprs)) {
|
||||
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
LHS = ExprError();
|
||||
}
|
||||
|
||||
@ -1889,16 +1851,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
PreferredType.enterFunctionArgument(Tok.getLocation(),
|
||||
RunSignatureHelp);
|
||||
}))) {
|
||||
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
// If we got an error when parsing expression list, we don't call
|
||||
// the CodeCompleteCall handler inside the parser. So call it here
|
||||
// to make sure we get overload suggestions even when we are in the
|
||||
// middle of a parameter.
|
||||
if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
|
||||
RunSignatureHelp();
|
||||
} else if (LHS.isInvalid()) {
|
||||
for (auto &E : ArgExprs)
|
||||
Actions.CorrectDelayedTyposInExpr(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1913,16 +1871,16 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
ArgExprs);
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
} else if (Tok.isNot(tok::r_paren)) {
|
||||
bool HadDelayedTypo = false;
|
||||
if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get())
|
||||
HadDelayedTypo = true;
|
||||
bool HadErrors = false;
|
||||
if (LHS.get()->containsErrors())
|
||||
HadErrors = true;
|
||||
for (auto &E : ArgExprs)
|
||||
if (Actions.CorrectDelayedTyposInExpr(E).get() != E)
|
||||
HadDelayedTypo = true;
|
||||
// If there were delayed typos in the LHS or ArgExprs, call SkipUntil
|
||||
// instead of PT.consumeClose() to avoid emitting extra diagnostics for
|
||||
// the unmatched l_paren.
|
||||
if (HadDelayedTypo)
|
||||
if (E->containsErrors())
|
||||
HadErrors = true;
|
||||
// If there were errors in the LHS or ArgExprs, call SkipUntil instead
|
||||
// of PT.consumeClose() to avoid emitting extra diagnostics for the
|
||||
// unmatched l_paren.
|
||||
if (HadErrors)
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
else
|
||||
PT.consumeClose();
|
||||
@ -2050,7 +2008,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
/*AllowConstructorName=*/
|
||||
getLangOpts().MicrosoftExt && SS.isNotEmpty(),
|
||||
/*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) {
|
||||
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
||||
LHS = ExprError();
|
||||
}
|
||||
|
||||
@ -2921,8 +2878,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
||||
do {
|
||||
BalancedDelimiterTracker TS(*this, tok::l_square);
|
||||
TS.consumeOpen();
|
||||
ExprResult NumElements =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult NumElements = ParseExpression();
|
||||
if (!NumElements.isUsable()) {
|
||||
ErrorFound = true;
|
||||
while (!SkipUntil(tok::r_square, tok::r_paren,
|
||||
@ -2936,7 +2892,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
||||
// Match the ')'.
|
||||
T.consumeClose();
|
||||
RParenLoc = T.getCloseLocation();
|
||||
Result = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
Result = ParseAssignmentExpression();
|
||||
if (ErrorFound) {
|
||||
Result = ExprError();
|
||||
} else if (!Result.isInvalid()) {
|
||||
@ -2948,12 +2904,6 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
||||
InMessageExpressionRAIIObject InMessage(*this, false);
|
||||
|
||||
Result = ParseExpression(TypeCastState::MaybeTypeCast);
|
||||
if (!getLangOpts().CPlusPlus && Result.isUsable()) {
|
||||
// Correct typos in non-C++ code earlier so that implicit-cast-like
|
||||
// expressions are parsed correctly.
|
||||
Result = Actions.CorrectDelayedTyposInExpr(Result);
|
||||
}
|
||||
|
||||
if (ExprType >= ParenParseOption::FoldExpr &&
|
||||
isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
|
||||
ExprType = ParenParseOption::FoldExpr;
|
||||
@ -3057,8 +3007,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
|
||||
// not evaluated."
|
||||
EnterExpressionEvaluationContext Unevaluated(
|
||||
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
|
||||
ControllingExpr =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
ControllingExpr = ParseAssignmentExpression();
|
||||
if (ControllingExpr.isInvalid()) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
return ExprError();
|
||||
@ -3104,8 +3053,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
|
||||
|
||||
// FIXME: These expressions should be parsed in a potentially potentially
|
||||
// evaluated context.
|
||||
ExprResult ER(
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
|
||||
ExprResult ER = ParseAssignmentExpression();
|
||||
if (ER.isInvalid()) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
return ExprError();
|
||||
@ -3199,8 +3147,7 @@ void Parser::injectEmbedTokens() {
|
||||
|
||||
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
|
||||
llvm::function_ref<void()> ExpressionStarts,
|
||||
bool FailImmediatelyOnInvalidExpr,
|
||||
bool EarlyTypoCorrection) {
|
||||
bool FailImmediatelyOnInvalidExpr) {
|
||||
bool SawError = false;
|
||||
while (true) {
|
||||
if (ExpressionStarts)
|
||||
@ -3213,9 +3160,6 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
|
||||
} else
|
||||
Expr = ParseAssignmentExpression();
|
||||
|
||||
if (EarlyTypoCorrection)
|
||||
Expr = Actions.CorrectDelayedTyposInExpr(Expr);
|
||||
|
||||
if (Tok.is(tok::ellipsis))
|
||||
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
|
||||
else if (Tok.is(tok::code_completion)) {
|
||||
@ -3244,14 +3188,6 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
|
||||
ConsumeToken();
|
||||
checkPotentialAngleBracketDelimiter(Comma);
|
||||
}
|
||||
if (SawError) {
|
||||
// Ensure typos get diagnosed when errors were encountered while parsing the
|
||||
// expression list.
|
||||
for (auto &E : Exprs) {
|
||||
ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
|
||||
if (Expr.isUsable()) E = Expr.get();
|
||||
}
|
||||
}
|
||||
return SawError;
|
||||
}
|
||||
|
||||
|
||||
@ -972,8 +972,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true);
|
||||
Init = ParseInitializer();
|
||||
if (!Init.isInvalid())
|
||||
Init = Actions.CorrectDelayedTyposInExpr(Init.get());
|
||||
|
||||
if (Tok.getLocation() != StartLoc) {
|
||||
// Back out the lexing of the token after the initializer.
|
||||
@ -1065,8 +1063,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||
// enclosing the lambda-expression, rather than in the context of the
|
||||
// lambda-expression itself.
|
||||
ParsedType InitCaptureType;
|
||||
if (Init.isUsable())
|
||||
Init = Actions.CorrectDelayedTyposInExpr(Init.get());
|
||||
if (Init.isUsable()) {
|
||||
NonTentativeAction([&] {
|
||||
// Get the pointer and store it in an lvalue, so we can use it as an
|
||||
@ -3202,8 +3198,7 @@ ExprResult Parser::ParseRequiresExpression() {
|
||||
// cv-qualifier-seq[opt] abstract-declarator[opt]
|
||||
BalancedDelimiterTracker ExprBraces(*this, tok::l_brace);
|
||||
ExprBraces.consumeOpen();
|
||||
ExprResult Expression =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult Expression = ParseExpression();
|
||||
if (!Expression.isUsable()) {
|
||||
ExprBraces.skipToEnd();
|
||||
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
|
||||
@ -3306,8 +3301,7 @@ ExprResult Parser::ParseRequiresExpression() {
|
||||
// C++ [expr.prim.req.nested]
|
||||
// nested-requirement:
|
||||
// 'requires' constraint-expression ';'
|
||||
ExprResult ConstraintExpr =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
|
||||
ExprResult ConstraintExpr = ParseConstraintExpression();
|
||||
if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) {
|
||||
SkipUntil(tok::semi, tok::r_brace,
|
||||
SkipUntilFlags::StopBeforeMatch);
|
||||
@ -3373,8 +3367,7 @@ ExprResult Parser::ParseRequiresExpression() {
|
||||
// simple-requirement:
|
||||
// expression ';'
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
ExprResult Expression =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult Expression = ParseExpression();
|
||||
if (!Expression.isUsable()) {
|
||||
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
|
||||
break;
|
||||
|
||||
@ -477,8 +477,6 @@ ExprResult Parser::ParseBraceInitializer() {
|
||||
if (Tok.is(tok::ellipsis))
|
||||
SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
|
||||
|
||||
SubElt = Actions.CorrectDelayedTyposInExpr(SubElt.get());
|
||||
|
||||
// If we couldn't parse the subelement, bail out.
|
||||
if (SubElt.isUsable()) {
|
||||
InitExprs.push_back(SubElt.get());
|
||||
|
||||
@ -2629,10 +2629,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
|
||||
if (!Tok.isSimpleTypeSpecifier(getLangOpts())) {
|
||||
// objc-receiver:
|
||||
// expression
|
||||
// Make sure any typos in the receiver are corrected or diagnosed, so that
|
||||
// proper recovery can happen. FIXME: Perhaps filter the corrected expr to
|
||||
// only the things that are valid ObjC receivers?
|
||||
ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult Receiver = ParseExpression();
|
||||
if (Receiver.isInvalid())
|
||||
return true;
|
||||
|
||||
@ -2809,7 +2806,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
|
||||
}
|
||||
|
||||
// Otherwise, an arbitrary expression can be the receiver of a send.
|
||||
ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult Res = ParseExpression();
|
||||
if (Res.isInvalid()) {
|
||||
SkipUntil(tok::r_square, StopAtSemi);
|
||||
return Res;
|
||||
@ -2930,8 +2927,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
|
||||
SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
|
||||
/// Parse the expression after ','
|
||||
ExprResult Res(ParseAssignmentExpression());
|
||||
if (Tok.is(tok::colon))
|
||||
Res = Actions.CorrectDelayedTyposInExpr(Res);
|
||||
if (Res.isInvalid()) {
|
||||
if (Tok.is(tok::colon)) {
|
||||
Diag(commaLoc, diag::note_extra_comma_message_arg) <<
|
||||
@ -3078,10 +3073,6 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
|
||||
return Res;
|
||||
}
|
||||
|
||||
Res = Actions.CorrectDelayedTyposInExpr(Res.get());
|
||||
if (Res.isInvalid())
|
||||
HasInvalidEltExpr = true;
|
||||
|
||||
// Parse the ellipsis that indicates a pack expansion.
|
||||
if (Tok.is(tok::ellipsis))
|
||||
Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
|
||||
@ -3108,7 +3099,6 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
|
||||
ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
|
||||
SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
|
||||
ConsumeBrace(); // consume the l_square.
|
||||
bool HasInvalidEltExpr = false;
|
||||
while (Tok.isNot(tok::r_brace)) {
|
||||
// Parse the comma separated key : value expressions.
|
||||
ExprResult KeyExpr;
|
||||
@ -3138,12 +3128,6 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
|
||||
return ValueExpr;
|
||||
}
|
||||
|
||||
// Check the key and value for possible typos
|
||||
KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
|
||||
ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
|
||||
if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
|
||||
HasInvalidEltExpr = true;
|
||||
|
||||
// Parse the ellipsis that designates this as a pack expansion. Do not
|
||||
// ActOnPackExpansion here, leave it to template instantiation time where
|
||||
// we can get better diagnostics.
|
||||
@ -3163,9 +3147,6 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
|
||||
}
|
||||
SourceLocation EndLoc = ConsumeBrace();
|
||||
|
||||
if (HasInvalidEltExpr)
|
||||
return ExprError();
|
||||
|
||||
// Create the ObjCDictionaryLiteral.
|
||||
return Actions.ObjC().BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
|
||||
Elements);
|
||||
|
||||
@ -653,7 +653,7 @@ ExprResult Parser::ParseOpenACCConditionExpr() {
|
||||
// it does in an if/while/etc (See ParseCXXCondition), however as it was
|
||||
// written with Fortran/C in mind, we're going to assume it just means an
|
||||
// 'expression evaluating to boolean'.
|
||||
ExprResult ER = getActions().CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult ER = ParseExpression();
|
||||
|
||||
if (!ER.isUsable())
|
||||
return ER;
|
||||
@ -761,12 +761,6 @@ Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
|
||||
if (!ER.isUsable())
|
||||
return {ER, OpenACCParseCanContinue::Cannot};
|
||||
|
||||
// Parsing can continue after the initial assignment expression parsing, so
|
||||
// even if there was a typo, we can continue.
|
||||
ER = getActions().CorrectDelayedTyposInExpr(ER);
|
||||
if (!ER.isUsable())
|
||||
return {ER, OpenACCParseCanContinue::Can};
|
||||
|
||||
return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get()),
|
||||
OpenACCParseCanContinue::Can};
|
||||
}
|
||||
@ -836,8 +830,7 @@ ExprResult Parser::ParseOpenACCSizeExpr(OpenACCClauseKind CK) {
|
||||
return getActions().OpenACC().ActOnOpenACCAsteriskSizeExpr(AsteriskLoc);
|
||||
}
|
||||
|
||||
ExprResult SizeExpr =
|
||||
getActions().CorrectDelayedTyposInExpr(ParseConstantExpression());
|
||||
ExprResult SizeExpr = ParseConstantExpression();
|
||||
|
||||
if (!SizeExpr.isUsable())
|
||||
return SizeExpr;
|
||||
@ -891,8 +884,7 @@ Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
|
||||
ConsumeToken();
|
||||
// Parse this as a const-expression, and we'll check its integer-ness/value
|
||||
// in CheckGangExpr.
|
||||
ExprResult Res =
|
||||
getActions().CorrectDelayedTyposInExpr(ParseConstantExpression());
|
||||
ExprResult Res = ParseConstantExpression();
|
||||
return {OpenACCGangKind::Dim, Res};
|
||||
}
|
||||
|
||||
@ -1089,8 +1081,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
|
||||
case OpenACCClauseKind::Collapse: {
|
||||
bool HasForce = tryParseAndConsumeSpecialTokenKind(
|
||||
*this, OpenACCSpecialTokenKind::Force, ClauseKind);
|
||||
ExprResult LoopCount =
|
||||
getActions().CorrectDelayedTyposInExpr(ParseConstantExpression());
|
||||
ExprResult LoopCount = ParseConstantExpression();
|
||||
if (LoopCount.isInvalid()) {
|
||||
Parens.skipToEnd();
|
||||
return OpenACCCanContinue();
|
||||
@ -1387,7 +1378,7 @@ ExprResult Parser::ParseOpenACCIDExpression() {
|
||||
/*isAddressOfOperand=*/false);
|
||||
}
|
||||
|
||||
return getActions().CorrectDelayedTyposInExpr(Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
std::variant<std::monostate, clang::StringLiteral *, IdentifierInfo *>
|
||||
@ -1414,9 +1405,8 @@ Parser::ParseOpenACCBindClauseArgument() {
|
||||
return std::monostate{};
|
||||
}
|
||||
|
||||
ExprResult Res =
|
||||
getActions().CorrectDelayedTyposInExpr(ParseStringLiteralExpression(
|
||||
/*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true));
|
||||
ExprResult Res = ParseStringLiteralExpression(
|
||||
/*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true);
|
||||
if (!Res.isUsable())
|
||||
return std::monostate{};
|
||||
return cast<StringLiteral>(Res.get());
|
||||
@ -1430,10 +1420,6 @@ Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCDirectiveKind DK,
|
||||
if (!Res.isUsable())
|
||||
return {Res, OpenACCParseCanContinue::Cannot};
|
||||
|
||||
Res = getActions().CorrectDelayedTyposInExpr(Res.get());
|
||||
if (!Res.isUsable())
|
||||
return {Res, OpenACCParseCanContinue::Can};
|
||||
|
||||
Res = getActions().OpenACC().ActOnVar(DK, CK, Res.get());
|
||||
|
||||
return {Res, OpenACCParseCanContinue::Can};
|
||||
|
||||
@ -3600,8 +3600,7 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo,
|
||||
while (Tok.isNot(tok::r_paren)) {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
|
||||
ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
||||
ExprResult PTExpr = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
|
||||
PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
|
||||
/*DiscardedValue=*/false);
|
||||
if (PTExpr.isUsable()) {
|
||||
@ -3662,8 +3661,7 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
|
||||
|
||||
// Parse the variable.
|
||||
SourceLocation VarLoc = Tok.getLocation();
|
||||
ExprResult InteropVarExpr =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
ExprResult InteropVarExpr = ParseAssignmentExpression();
|
||||
if (!InteropVarExpr.isUsable()) {
|
||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
@ -4288,8 +4286,7 @@ ExprResult Parser::ParseOpenMPIteratorsExpr() {
|
||||
// Parse <begin>
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
|
||||
ExprResult Begin = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
||||
ExprResult Begin = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
|
||||
Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc,
|
||||
/*DiscardedValue=*/false);
|
||||
// Parse ':'.
|
||||
@ -4300,8 +4297,7 @@ ExprResult Parser::ParseOpenMPIteratorsExpr() {
|
||||
// Parse <end>
|
||||
Loc = Tok.getLocation();
|
||||
LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
|
||||
ExprResult End = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
||||
ExprResult End = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
|
||||
End = Actions.ActOnFinishFullExpr(End.get(), Loc,
|
||||
/*DiscardedValue=*/false);
|
||||
|
||||
@ -4314,8 +4310,7 @@ ExprResult Parser::ParseOpenMPIteratorsExpr() {
|
||||
// Parse <step>
|
||||
Loc = Tok.getLocation();
|
||||
LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
|
||||
Step = Actions.CorrectDelayedTyposInExpr(
|
||||
ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
||||
Step = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
|
||||
Step = Actions.ActOnFinishFullExpr(Step.get(), Loc,
|
||||
/*DiscardedValue=*/false);
|
||||
}
|
||||
@ -4797,7 +4792,6 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
|
||||
Tail = ParseOpenMPIteratorsExpr();
|
||||
}
|
||||
Tail = Actions.CorrectDelayedTyposInExpr(Tail);
|
||||
Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),
|
||||
/*DiscardedValue=*/false);
|
||||
if (Tail.isUsable() || Data.AllocateAlignment) {
|
||||
@ -4858,8 +4852,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
|
||||
if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) {
|
||||
// Parse variable
|
||||
ExprResult VarExpr =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
ExprResult VarExpr = ParseAssignmentExpression();
|
||||
if (VarExpr.isUsable()) {
|
||||
Vars.push_back(VarExpr.get());
|
||||
} else {
|
||||
@ -4896,6 +4889,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
SourceLocation ELoc = ConsumeToken();
|
||||
|
||||
if (getLangOpts().OpenMP >= 52 && Kind == OMPC_linear) {
|
||||
bool Malformed = false;
|
||||
while (Tok.isNot(tok::r_paren)) {
|
||||
if (Tok.is(tok::identifier)) {
|
||||
// identifier could be a linear kind (val, uval, ref) or step
|
||||
@ -4932,6 +4926,11 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
ModifierFound = true;
|
||||
} else {
|
||||
StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());
|
||||
if (!StepFound) {
|
||||
Malformed = true;
|
||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// parse an integer expression as step size
|
||||
@ -4943,7 +4942,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end))
|
||||
break;
|
||||
}
|
||||
if (!StepFound && !ModifierFound)
|
||||
if (!Malformed && !StepFound && !ModifierFound)
|
||||
Diag(ELoc, diag::err_expected_expression);
|
||||
} else {
|
||||
// for OMPC_aligned and OMPC_linear (with OpenMP <= 5.1)
|
||||
|
||||
@ -602,7 +602,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
|
||||
{
|
||||
ParseScopeFlags FilterScope(this, getCurScope()->getFlags() |
|
||||
Scope::SEHFilterScope);
|
||||
FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
FilterExpr = ParseExpression();
|
||||
}
|
||||
|
||||
if (getLangOpts().Borland) {
|
||||
@ -1832,11 +1832,7 @@ StmtResult Parser::ParseDoStatement() {
|
||||
|
||||
SourceLocation Start = Tok.getLocation();
|
||||
ExprResult Cond = ParseExpression();
|
||||
// Correct the typos in condition before closing the scope.
|
||||
if (Cond.isUsable())
|
||||
Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr,
|
||||
/*RecoverUncorrectedTypos=*/true);
|
||||
else {
|
||||
if (!Cond.isUsable()) {
|
||||
if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace))
|
||||
SkipUntil(tok::semi);
|
||||
Cond = Actions.CreateRecoveryExpr(
|
||||
@ -2018,7 +2014,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
||||
}
|
||||
} else {
|
||||
ProhibitAttributes(attrs);
|
||||
Value = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
Value = ParseExpression();
|
||||
|
||||
ForEach = isTokIdentifier_in();
|
||||
|
||||
@ -2177,12 +2173,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
||||
StmtResult ForEachStmt;
|
||||
|
||||
if (ForRangeInfo.ParsedForRangeDecl()) {
|
||||
ExprResult CorrectedRange =
|
||||
Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get());
|
||||
ForRangeStmt = Actions.ActOnCXXForRangeStmt(
|
||||
getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
|
||||
ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(),
|
||||
T.getCloseLocation(), Sema::BFRK_Build,
|
||||
ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc,
|
||||
ForRangeInfo.RangeExpr.get(), T.getCloseLocation(), Sema::BFRK_Build,
|
||||
ForRangeInfo.LifetimeExtendTemps);
|
||||
} else if (ForEach) {
|
||||
// Similarly, we need to do the semantic analysis for a for-range
|
||||
|
||||
@ -864,7 +864,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
|
||||
// Read the parenthesized expression.
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
||||
ExprResult Res = ParseExpression();
|
||||
T.consumeClose();
|
||||
if (Res.isInvalid()) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
|
||||
@ -296,8 +296,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExprResult ConstraintExprResult =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
|
||||
ExprResult ConstraintExprResult = ParseConstraintExpression();
|
||||
if (ConstraintExprResult.isInvalid()) {
|
||||
SkipUntil(tok::semi);
|
||||
if (D)
|
||||
|
||||
@ -1227,15 +1227,6 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
|
||||
assert(LateParsedInstantiations.empty() &&
|
||||
"end of TU template instantiation should not create more "
|
||||
"late-parsed templates");
|
||||
|
||||
// Report diagnostics for uncorrected delayed typos. Ideally all of them
|
||||
// should have been corrected by that time, but it is very hard to cover all
|
||||
// cases in practice.
|
||||
for (const auto &Typo : DelayedTypos) {
|
||||
// We pass an empty TypoCorrection to indicate no correction was performed.
|
||||
Typo.second.DiagHandler(TypoCorrection());
|
||||
}
|
||||
DelayedTypos.clear();
|
||||
}
|
||||
|
||||
void Sema::ActOnEndOfTranslationUnit() {
|
||||
|
||||
@ -2648,8 +2648,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
||||
bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete;
|
||||
ExprResult Res =
|
||||
BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete);
|
||||
if (Res.isInvalid())
|
||||
CorrectDelayedTyposInExpr(TheCallResult.get());
|
||||
return Res;
|
||||
}
|
||||
case Builtin::BI__builtin_dump_struct:
|
||||
|
||||
@ -309,15 +309,6 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
|
||||
if (Result.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
// We meant exactly what we asked for. No need for typo correction.
|
||||
if (auto *TE = dyn_cast<TypoExpr>(Result.get())) {
|
||||
S.clearDelayedTypo(TE);
|
||||
S.Diag(Loc, diag::err_no_member)
|
||||
<< NameInfo.getName() << Base->getType()->getAsCXXRecordDecl()
|
||||
<< Base->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
auto EndLoc = Args.empty() ? Loc : Args.back()->getEndLoc();
|
||||
return S.BuildCallExpr(nullptr, Result.get(), Loc, Args, EndLoc, nullptr);
|
||||
}
|
||||
@ -811,7 +802,6 @@ ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
return ExprError();
|
||||
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
@ -970,7 +960,6 @@ ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
return ExprError();
|
||||
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
@ -1025,7 +1014,6 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
|
||||
|
||||
StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return StmtError();
|
||||
}
|
||||
return BuildCoreturnStmt(Loc, E);
|
||||
|
||||
@ -13584,7 +13584,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
// If there is no declaration, there was an error parsing it. Just ignore
|
||||
// the initializer.
|
||||
if (!RealDecl) {
|
||||
CorrectDelayedTyposInExpr(Init, dyn_cast_or_null<VarDecl>(RealDecl));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -13607,12 +13606,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
}
|
||||
|
||||
if (VDecl->isInvalidDecl()) {
|
||||
ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl);
|
||||
SmallVector<Expr *> SubExprs;
|
||||
if (Res.isUsable())
|
||||
SubExprs.push_back(Res.get());
|
||||
ExprResult Recovery =
|
||||
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), SubExprs);
|
||||
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), {Init});
|
||||
if (Expr *E = Recovery.get())
|
||||
VDecl->setInit(E);
|
||||
return;
|
||||
@ -13627,23 +13622,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
|
||||
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||
if (VDecl->getType()->isUndeducedType()) {
|
||||
// Attempt typo correction early so that the type of the init expression can
|
||||
// be deduced based on the chosen correction if the original init contains a
|
||||
// TypoExpr.
|
||||
ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl);
|
||||
if (!Res.isUsable()) {
|
||||
// There are unresolved typos in Init, just drop them.
|
||||
// FIXME: improve the recovery strategy to preserve the Init.
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
if (Res.get()->containsErrors()) {
|
||||
if (Init->containsErrors()) {
|
||||
// Invalidate the decl as we don't know the type for recovery-expr yet.
|
||||
RealDecl->setInvalidDecl();
|
||||
VDecl->setInit(Res.get());
|
||||
VDecl->setInit(Init);
|
||||
return;
|
||||
}
|
||||
Init = Res.get();
|
||||
|
||||
if (DeduceVariableDeclarationType(VDecl, DirectInit, Init))
|
||||
return;
|
||||
@ -13789,23 +13773,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
InitializedFromParenListExpr = true;
|
||||
}
|
||||
|
||||
// Try to correct any TypoExprs in the initialization arguments.
|
||||
for (size_t Idx = 0; Idx < Args.size(); ++Idx) {
|
||||
ExprResult Res = CorrectDelayedTyposInExpr(
|
||||
Args[Idx], VDecl, /*RecoverUncorrectedTypos=*/true,
|
||||
[this, Entity, Kind](Expr *E) {
|
||||
InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E));
|
||||
return Init.Failed() ? ExprError() : E;
|
||||
});
|
||||
if (!Res.isUsable()) {
|
||||
VDecl->setInvalidDecl();
|
||||
} else if (Res.get() != Args[Idx]) {
|
||||
Args[Idx] = Res.get();
|
||||
}
|
||||
}
|
||||
if (VDecl->isInvalidDecl())
|
||||
return;
|
||||
|
||||
InitializationSequence InitSeq(*this, Entity, Kind, Args,
|
||||
/*TopLevelOfInitList=*/false,
|
||||
/*TreatUnavailableAsInvalid=*/false);
|
||||
|
||||
@ -4154,10 +4154,6 @@ ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) {
|
||||
if (ConstraintExpr.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
ConstraintExpr = CorrectDelayedTyposInExpr(ConstraintExpr);
|
||||
if (ConstraintExpr.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
if (DiagnoseUnexpandedParameterPack(ConstraintExpr.get(),
|
||||
UPPC_RequiresClause))
|
||||
return ExprError();
|
||||
@ -4207,23 +4203,20 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
|
||||
return;
|
||||
}
|
||||
|
||||
ExprResult Init = CorrectDelayedTyposInExpr(InitExpr, /*InitDecl=*/nullptr,
|
||||
/*RecoverUncorrectedTypos=*/true);
|
||||
assert(Init.isUsable() && "Init should at least have a RecoveryExpr");
|
||||
if (!FD->getType()->isDependentType() && !Init.get()->isTypeDependent()) {
|
||||
Init = ConvertMemberDefaultInitExpression(FD, Init.get(), InitLoc);
|
||||
if (!FD->getType()->isDependentType() && !InitExpr.get()->isTypeDependent()) {
|
||||
InitExpr = ConvertMemberDefaultInitExpression(FD, InitExpr.get(), InitLoc);
|
||||
// C++11 [class.base.init]p7:
|
||||
// The initialization of each base and member constitutes a
|
||||
// full-expression.
|
||||
if (!Init.isInvalid())
|
||||
Init = ActOnFinishFullExpr(Init.get(), /*DiscarededValue=*/false);
|
||||
if (Init.isInvalid()) {
|
||||
if (!InitExpr.isInvalid())
|
||||
InitExpr = ActOnFinishFullExpr(InitExpr.get(), /*DiscarededValue=*/false);
|
||||
if (InitExpr.isInvalid()) {
|
||||
FD->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FD->setInClassInitializer(Init.get());
|
||||
FD->setInClassInitializer(InitExpr.get());
|
||||
}
|
||||
|
||||
/// Find the direct and/or virtual base specifiers that
|
||||
@ -4393,13 +4386,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
|
||||
SourceLocation IdLoc,
|
||||
Expr *Init,
|
||||
SourceLocation EllipsisLoc) {
|
||||
ExprResult Res = CorrectDelayedTyposInExpr(Init, /*InitDecl=*/nullptr,
|
||||
/*RecoverUncorrectedTypos=*/true);
|
||||
if (!Res.isUsable())
|
||||
return true;
|
||||
Init = Res.get();
|
||||
|
||||
if (!ConstructorD)
|
||||
if (!ConstructorD || !Init)
|
||||
return true;
|
||||
|
||||
AdjustDeclIfTemplate(ConstructorD);
|
||||
|
||||
@ -1368,7 +1368,6 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
|
||||
case Expr::UnaryExprOrTypeTraitExprClass:
|
||||
case Expr::UnresolvedLookupExprClass:
|
||||
case Expr::UnresolvedMemberExprClass:
|
||||
case Expr::TypoExprClass:
|
||||
// FIXME: Many of the above can throw.
|
||||
return CT_Cannot;
|
||||
|
||||
|
||||
@ -2544,8 +2544,7 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
|
||||
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
|
||||
CorrectionCandidateCallback &CCC,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
ArrayRef<Expr *> Args, DeclContext *LookupCtx,
|
||||
TypoExpr **Out) {
|
||||
ArrayRef<Expr *> Args, DeclContext *LookupCtx) {
|
||||
DeclarationName Name = R.getLookupName();
|
||||
SourceRange NameRange = R.getLookupNameInfo().getSourceRange();
|
||||
|
||||
@ -2604,21 +2603,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
|
||||
|
||||
// We didn't find anything, so try to correct for a typo.
|
||||
TypoCorrection Corrected;
|
||||
if (S && Out) {
|
||||
assert(!ExplicitTemplateArgs &&
|
||||
"Diagnosing an empty lookup with explicit template args!");
|
||||
*Out = CorrectTypoDelayed(
|
||||
R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC,
|
||||
[=](const TypoCorrection &TC) {
|
||||
emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, NameRange,
|
||||
diagnostic, diagnostic_suggest);
|
||||
},
|
||||
nullptr, CorrectTypoKind::ErrorRecovery, LookupCtx);
|
||||
if (*Out)
|
||||
return true;
|
||||
} else if (S && (Corrected = CorrectTypo(
|
||||
R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC,
|
||||
CorrectTypoKind::ErrorRecovery, LookupCtx))) {
|
||||
if (S && (Corrected =
|
||||
CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
|
||||
CCC, CorrectTypoKind::ErrorRecovery, LookupCtx))) {
|
||||
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
|
||||
bool DroppedSpecifier =
|
||||
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
|
||||
@ -2880,7 +2867,6 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||
|
||||
// If this name wasn't predeclared and if this is not a function
|
||||
// call, diagnose the problem.
|
||||
TypoExpr *TE = nullptr;
|
||||
DefaultFilterCCC DefaultValidator(II, SS.isValid() ? SS.getScopeRep()
|
||||
: nullptr);
|
||||
DefaultValidator.IsAddressOfOperand = IsAddressOfOperand;
|
||||
@ -2896,29 +2882,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||
// a template name, but we happen to have always already looked up the name
|
||||
// before we get here if it must be a template name.
|
||||
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
|
||||
{}, nullptr, &TE)) {
|
||||
if (TE && KeywordReplacement) {
|
||||
auto &State = getTypoExprState(TE);
|
||||
auto BestTC = State.Consumer->getNextCorrection();
|
||||
if (BestTC.isKeyword()) {
|
||||
auto *II = BestTC.getCorrectionAsIdentifierInfo();
|
||||
if (State.DiagHandler)
|
||||
State.DiagHandler(BestTC);
|
||||
KeywordReplacement->startToken();
|
||||
KeywordReplacement->setKind(II->getTokenID());
|
||||
KeywordReplacement->setIdentifierInfo(II);
|
||||
KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin());
|
||||
// Clean up the state associated with the TypoExpr, since it has
|
||||
// now been diagnosed (without a call to CorrectDelayedTyposInExpr).
|
||||
clearDelayedTypo(TE);
|
||||
// Signal that a correction to a keyword was performed by returning a
|
||||
// valid-but-null ExprResult.
|
||||
return (Expr*)nullptr;
|
||||
}
|
||||
State.Consumer->resetCorrectionStream();
|
||||
}
|
||||
return TE ? TE : ExprError();
|
||||
}
|
||||
{}, nullptr))
|
||||
return ExprError();
|
||||
|
||||
assert(!R.empty() &&
|
||||
"DiagnoseEmptyLookup returned false but added no results");
|
||||
@ -7009,40 +6974,6 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||
CurFPFeatureOverrides(), NumParams, UsesADL);
|
||||
}
|
||||
|
||||
if (!Context.isDependenceAllowed()) {
|
||||
// Forget about the nulled arguments since typo correction
|
||||
// do not handle them well.
|
||||
TheCall->shrinkNumArgs(Args.size());
|
||||
// C cannot always handle TypoExpr nodes in builtin calls and direct
|
||||
// function calls as their argument checking don't necessarily handle
|
||||
// dependent types properly, so make sure any TypoExprs have been
|
||||
// dealt with.
|
||||
ExprResult Result = CorrectDelayedTyposInExpr(TheCall);
|
||||
if (!Result.isUsable()) return ExprError();
|
||||
CallExpr *TheOldCall = TheCall;
|
||||
TheCall = dyn_cast<CallExpr>(Result.get());
|
||||
bool CorrectedTypos = TheCall != TheOldCall;
|
||||
if (!TheCall) return Result;
|
||||
Args = llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs());
|
||||
|
||||
// A new call expression node was created if some typos were corrected.
|
||||
// However it may not have been constructed with enough storage. In this
|
||||
// case, rebuild the node with enough storage. The waste of space is
|
||||
// immaterial since this only happens when some typos were corrected.
|
||||
if (CorrectedTypos && Args.size() < NumParams) {
|
||||
if (Config)
|
||||
TheCall = CUDAKernelCallExpr::Create(
|
||||
Context, Fn, cast<CallExpr>(Config), Args, ResultTy, VK_PRValue,
|
||||
RParenLoc, CurFPFeatureOverrides(), NumParams);
|
||||
else
|
||||
TheCall =
|
||||
CallExpr::Create(Context, Fn, Args, ResultTy, VK_PRValue, RParenLoc,
|
||||
CurFPFeatureOverrides(), NumParams, UsesADL);
|
||||
}
|
||||
// We can now handle the nulled arguments for the default arguments.
|
||||
TheCall->setNumArgsUnsafe(std::max<unsigned>(Args.size(), NumParams));
|
||||
}
|
||||
|
||||
// Bail out early if calling a builtin with custom type checking.
|
||||
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) {
|
||||
ExprResult E = CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall);
|
||||
@ -7933,12 +7864,6 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
// Check that there are no default arguments (C++ only).
|
||||
CheckExtraCXXDefaultArguments(D);
|
||||
} else {
|
||||
// Make sure any TypoExprs have been dealt with.
|
||||
ExprResult Res = CorrectDelayedTyposInExpr(CastExpr);
|
||||
if (!Res.isUsable())
|
||||
return ExprError();
|
||||
CastExpr = Res.get();
|
||||
}
|
||||
|
||||
checkUnusedDeclAttributes(D);
|
||||
@ -8984,30 +8909,6 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
|
||||
SourceLocation ColonLoc,
|
||||
Expr *CondExpr, Expr *LHSExpr,
|
||||
Expr *RHSExpr) {
|
||||
if (!Context.isDependenceAllowed()) {
|
||||
// C cannot handle TypoExpr nodes in the condition because it
|
||||
// doesn't handle dependent types properly, so make sure any TypoExprs have
|
||||
// been dealt with before checking the operands.
|
||||
ExprResult CondResult = CorrectDelayedTyposInExpr(CondExpr);
|
||||
ExprResult LHSResult = CorrectDelayedTyposInExpr(LHSExpr);
|
||||
ExprResult RHSResult = CorrectDelayedTyposInExpr(RHSExpr);
|
||||
|
||||
if (!CondResult.isUsable())
|
||||
return ExprError();
|
||||
|
||||
if (LHSExpr) {
|
||||
if (!LHSResult.isUsable())
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (!RHSResult.isUsable())
|
||||
return ExprError();
|
||||
|
||||
CondExpr = CondResult.get();
|
||||
LHSExpr = LHSResult.get();
|
||||
RHSExpr = RHSResult.get();
|
||||
}
|
||||
|
||||
// If this is the gnu "x ?: y" extension, analyze the types as though the LHS
|
||||
// was the condition.
|
||||
OpaqueValueExpr *opaqueValue = nullptr;
|
||||
@ -15068,28 +14969,6 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
|
||||
return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
|
||||
}
|
||||
|
||||
static std::pair<ExprResult, ExprResult>
|
||||
CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
|
||||
Expr *RHSExpr) {
|
||||
ExprResult LHS = LHSExpr, RHS = RHSExpr;
|
||||
if (!S.Context.isDependenceAllowed()) {
|
||||
// C cannot handle TypoExpr nodes on either side of a binop because it
|
||||
// doesn't handle dependent types properly, so make sure any TypoExprs have
|
||||
// been dealt with before checking the operands.
|
||||
LHS = S.CorrectDelayedTyposInExpr(LHS);
|
||||
RHS = S.CorrectDelayedTyposInExpr(
|
||||
RHS, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false,
|
||||
[Opc, LHS](Expr *E) {
|
||||
if (Opc != BO_Assign)
|
||||
return ExprResult(E);
|
||||
// Avoid correcting the RHS to the same Expr as the LHS.
|
||||
Decl *D = getDeclFromExpr(E);
|
||||
return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
|
||||
});
|
||||
}
|
||||
return std::make_pair(LHS, RHS);
|
||||
}
|
||||
|
||||
/// Returns true if conversion between vectors of halfs and vectors of floats
|
||||
/// is needed.
|
||||
static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
|
||||
@ -15146,7 +15025,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||
ExprObjectKind OK = OK_Ordinary;
|
||||
bool ConvertHalfVec = false;
|
||||
|
||||
std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
|
||||
if (!LHS.isUsable() || !RHS.isUsable())
|
||||
return ExprError();
|
||||
|
||||
@ -15662,12 +15540,8 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
|
||||
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
|
||||
BinaryOperatorKind Opc, Expr *LHSExpr,
|
||||
Expr *RHSExpr, bool ForFoldExpression) {
|
||||
ExprResult LHS, RHS;
|
||||
std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
|
||||
if (!LHS.isUsable() || !RHS.isUsable())
|
||||
if (!LHSExpr || !RHSExpr)
|
||||
return ExprError();
|
||||
LHSExpr = LHS.get();
|
||||
RHSExpr = RHS.get();
|
||||
|
||||
// We want to end up calling one of SemaPseudoObject::checkAssignment
|
||||
// (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
|
||||
@ -18194,8 +18068,6 @@ HandleImmediateInvocations(Sema &SemaRef,
|
||||
|
||||
void Sema::PopExpressionEvaluationContext() {
|
||||
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
|
||||
unsigned NumTypos = Rec.NumTypos;
|
||||
|
||||
if (!Rec.Lambdas.empty()) {
|
||||
using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind;
|
||||
if (!getLangOpts().CPlusPlus20 &&
|
||||
@ -18263,9 +18135,6 @@ void Sema::PopExpressionEvaluationContext() {
|
||||
|
||||
// Pop the current expression evaluation context off the stack.
|
||||
ExprEvalContexts.pop_back();
|
||||
|
||||
// The global expression evaluation context record is never popped.
|
||||
ExprEvalContexts.back().NumTypos += NumTypos;
|
||||
}
|
||||
|
||||
void Sema::DiscardCleanupsInEvaluationContext() {
|
||||
@ -20023,8 +19892,6 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) {
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
||||
Res = CorrectDelayedTyposInExpr(Res);
|
||||
|
||||
if (!Res.isUsable())
|
||||
return Res;
|
||||
|
||||
@ -21350,15 +21217,6 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
|
||||
}
|
||||
|
||||
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
|
||||
if (!Context.isDependenceAllowed()) {
|
||||
// C cannot handle TypoExpr nodes on either side of a binop because it
|
||||
// doesn't handle dependent types properly, so make sure any TypoExprs have
|
||||
// been dealt with before checking the operands.
|
||||
ExprResult Result = CorrectDelayedTyposInExpr(E);
|
||||
if (!Result.isUsable()) return ExprError();
|
||||
E = Result.get();
|
||||
}
|
||||
|
||||
const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType();
|
||||
if (!placeholderType) return E;
|
||||
|
||||
|
||||
@ -1500,13 +1500,7 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
|
||||
|
||||
auto Result = BuildCXXTypeConstructExpr(TInfo, LParenOrBraceLoc, exprs,
|
||||
RParenOrBraceLoc, ListInitialization);
|
||||
// Avoid creating a non-type-dependent expression that contains typos.
|
||||
// Non-type-dependent expressions are liable to be discarded without
|
||||
// checking for embedded typos.
|
||||
if (!Result.isInvalid() && Result.get()->isInstantiationDependent() &&
|
||||
!Result.get()->isTypeDependent())
|
||||
Result = CorrectDelayedTyposInExpr(Result.get());
|
||||
else if (Result.isInvalid())
|
||||
if (Result.isInvalid())
|
||||
Result = CreateRecoveryExpr(TInfo->getTypeLoc().getBeginLoc(),
|
||||
RParenOrBraceLoc, exprs, Ty);
|
||||
return Result;
|
||||
@ -7698,372 +7692,6 @@ static ExprResult attemptRecovery(Sema &SemaRef,
|
||||
/*AcceptInvalidDecl*/ true);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class FindTypoExprs : public DynamicRecursiveASTVisitor {
|
||||
llvm::SmallSetVector<TypoExpr *, 2> &TypoExprs;
|
||||
|
||||
public:
|
||||
explicit FindTypoExprs(llvm::SmallSetVector<TypoExpr *, 2> &TypoExprs)
|
||||
: TypoExprs(TypoExprs) {}
|
||||
bool VisitTypoExpr(TypoExpr *TE) override {
|
||||
TypoExprs.insert(TE);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TransformTypos : public TreeTransform<TransformTypos> {
|
||||
typedef TreeTransform<TransformTypos> BaseTransform;
|
||||
|
||||
VarDecl *InitDecl; // A decl to avoid as a correction because it is in the
|
||||
// process of being initialized.
|
||||
llvm::function_ref<ExprResult(Expr *)> ExprFilter;
|
||||
llvm::SmallSetVector<TypoExpr *, 2> TypoExprs, AmbiguousTypoExprs;
|
||||
llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache;
|
||||
llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution;
|
||||
|
||||
/// Emit diagnostics for all of the TypoExprs encountered.
|
||||
///
|
||||
/// If the TypoExprs were successfully corrected, then the diagnostics should
|
||||
/// suggest the corrections. Otherwise the diagnostics will not suggest
|
||||
/// anything (having been passed an empty TypoCorrection).
|
||||
///
|
||||
/// If we've failed to correct due to ambiguous corrections, we need to
|
||||
/// be sure to pass empty corrections and replacements. Otherwise it's
|
||||
/// possible that the Consumer has a TypoCorrection that failed to ambiguity
|
||||
/// and we don't want to report those diagnostics.
|
||||
void EmitAllDiagnostics(bool IsAmbiguous) {
|
||||
for (TypoExpr *TE : TypoExprs) {
|
||||
auto &State = SemaRef.getTypoExprState(TE);
|
||||
if (State.DiagHandler) {
|
||||
TypoCorrection TC = IsAmbiguous
|
||||
? TypoCorrection() : State.Consumer->getCurrentCorrection();
|
||||
ExprResult Replacement = IsAmbiguous ? ExprError() : TransformCache[TE];
|
||||
|
||||
// Extract the NamedDecl from the transformed TypoExpr and add it to the
|
||||
// TypoCorrection, replacing the existing decls. This ensures the right
|
||||
// NamedDecl is used in diagnostics e.g. in the case where overload
|
||||
// resolution was used to select one from several possible decls that
|
||||
// had been stored in the TypoCorrection.
|
||||
if (auto *ND = getDeclFromExpr(
|
||||
Replacement.isInvalid() ? nullptr : Replacement.get()))
|
||||
TC.setCorrectionDecl(ND);
|
||||
|
||||
State.DiagHandler(TC);
|
||||
}
|
||||
SemaRef.clearDelayedTypo(TE);
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to advance the typo correction state of the first unfinished TypoExpr.
|
||||
/// We allow advancement of the correction stream by removing it from the
|
||||
/// TransformCache which allows `TransformTypoExpr` to advance during the
|
||||
/// next transformation attempt.
|
||||
///
|
||||
/// Any substitution attempts for the previous TypoExprs (which must have been
|
||||
/// finished) will need to be retried since it's possible that they will now
|
||||
/// be invalid given the latest advancement.
|
||||
///
|
||||
/// We need to be sure that we're making progress - it's possible that the
|
||||
/// tree is so malformed that the transform never makes it to the
|
||||
/// `TransformTypoExpr`.
|
||||
///
|
||||
/// Returns true if there are any untried correction combinations.
|
||||
bool CheckAndAdvanceTypoExprCorrectionStreams() {
|
||||
for (auto *TE : TypoExprs) {
|
||||
auto &State = SemaRef.getTypoExprState(TE);
|
||||
TransformCache.erase(TE);
|
||||
if (!State.Consumer->hasMadeAnyCorrectionProgress())
|
||||
return false;
|
||||
if (!State.Consumer->finished())
|
||||
return true;
|
||||
State.Consumer->resetCorrectionStream();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NamedDecl *getDeclFromExpr(Expr *E) {
|
||||
if (auto *OE = dyn_cast_or_null<OverloadExpr>(E))
|
||||
E = OverloadResolution[OE];
|
||||
|
||||
if (!E)
|
||||
return nullptr;
|
||||
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
|
||||
return DRE->getFoundDecl();
|
||||
if (auto *ME = dyn_cast<MemberExpr>(E))
|
||||
return ME->getFoundDecl();
|
||||
// FIXME: Add any other expr types that could be seen by the delayed typo
|
||||
// correction TreeTransform for which the corresponding TypoCorrection could
|
||||
// contain multiple decls.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExprResult TryTransform(Expr *E) {
|
||||
Sema::SFINAETrap Trap(SemaRef);
|
||||
ExprResult Res = TransformExpr(E);
|
||||
if (Trap.hasErrorOccurred() || Res.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
return ExprFilter(Res.get());
|
||||
}
|
||||
|
||||
// Since correcting typos may intoduce new TypoExprs, this function
|
||||
// checks for new TypoExprs and recurses if it finds any. Note that it will
|
||||
// only succeed if it is able to correct all typos in the given expression.
|
||||
ExprResult CheckForRecursiveTypos(ExprResult Res, bool &IsAmbiguous) {
|
||||
if (Res.isInvalid()) {
|
||||
return Res;
|
||||
}
|
||||
// Check to see if any new TypoExprs were created. If so, we need to recurse
|
||||
// to check their validity.
|
||||
Expr *FixedExpr = Res.get();
|
||||
|
||||
auto SavedTypoExprs = std::move(TypoExprs);
|
||||
auto SavedAmbiguousTypoExprs = std::move(AmbiguousTypoExprs);
|
||||
TypoExprs.clear();
|
||||
AmbiguousTypoExprs.clear();
|
||||
|
||||
FindTypoExprs(TypoExprs).TraverseStmt(FixedExpr);
|
||||
if (!TypoExprs.empty()) {
|
||||
// Recurse to handle newly created TypoExprs. If we're not able to
|
||||
// handle them, discard these TypoExprs.
|
||||
ExprResult RecurResult =
|
||||
RecursiveTransformLoop(FixedExpr, IsAmbiguous);
|
||||
if (RecurResult.isInvalid()) {
|
||||
Res = ExprError();
|
||||
// Recursive corrections didn't work, wipe them away and don't add
|
||||
// them to the TypoExprs set. Remove them from Sema's TypoExpr list
|
||||
// since we don't want to clear them twice. Note: it's possible the
|
||||
// TypoExprs were created recursively and thus won't be in our
|
||||
// Sema's TypoExprs - they were created in our `RecursiveTransformLoop`.
|
||||
auto &SemaTypoExprs = SemaRef.TypoExprs;
|
||||
for (auto *TE : TypoExprs) {
|
||||
TransformCache.erase(TE);
|
||||
SemaRef.clearDelayedTypo(TE);
|
||||
|
||||
auto SI = find(SemaTypoExprs, TE);
|
||||
if (SI != SemaTypoExprs.end()) {
|
||||
SemaTypoExprs.erase(SI);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TypoExpr is valid: add newly created TypoExprs since we were
|
||||
// able to correct them.
|
||||
Res = RecurResult;
|
||||
SavedTypoExprs.set_union(TypoExprs);
|
||||
}
|
||||
}
|
||||
|
||||
TypoExprs = std::move(SavedTypoExprs);
|
||||
AmbiguousTypoExprs = std::move(SavedAmbiguousTypoExprs);
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
// Try to transform the given expression, looping through the correction
|
||||
// candidates with `CheckAndAdvanceTypoExprCorrectionStreams`.
|
||||
//
|
||||
// If valid ambiguous typo corrections are seen, `IsAmbiguous` is set to
|
||||
// true and this method immediately will return an `ExprError`.
|
||||
ExprResult RecursiveTransformLoop(Expr *E, bool &IsAmbiguous) {
|
||||
ExprResult Res;
|
||||
auto SavedTypoExprs = std::move(SemaRef.TypoExprs);
|
||||
SemaRef.TypoExprs.clear();
|
||||
|
||||
while (true) {
|
||||
Res = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous);
|
||||
|
||||
// Recursion encountered an ambiguous correction. This means that our
|
||||
// correction itself is ambiguous, so stop now.
|
||||
if (IsAmbiguous)
|
||||
break;
|
||||
|
||||
// If the transform is still valid after checking for any new typos,
|
||||
// it's good to go.
|
||||
if (!Res.isInvalid())
|
||||
break;
|
||||
|
||||
// The transform was invalid, see if we have any TypoExprs with untried
|
||||
// correction candidates.
|
||||
if (!CheckAndAdvanceTypoExprCorrectionStreams())
|
||||
break;
|
||||
}
|
||||
|
||||
// If we found a valid result, double check to make sure it's not ambiguous.
|
||||
if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) {
|
||||
auto SavedTransformCache =
|
||||
llvm::SmallDenseMap<TypoExpr *, ExprResult, 2>(TransformCache);
|
||||
|
||||
// Ensure none of the TypoExprs have multiple typo correction candidates
|
||||
// with the same edit length that pass all the checks and filters.
|
||||
while (!AmbiguousTypoExprs.empty()) {
|
||||
auto TE = AmbiguousTypoExprs.back();
|
||||
|
||||
// TryTransform itself can create new Typos, adding them to the TypoExpr map
|
||||
// and invalidating our TypoExprState, so always fetch it instead of storing.
|
||||
SemaRef.getTypoExprState(TE).Consumer->saveCurrentPosition();
|
||||
|
||||
TypoCorrection TC = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection();
|
||||
TypoCorrection Next;
|
||||
do {
|
||||
// Fetch the next correction by erasing the typo from the cache and calling
|
||||
// `TryTransform` which will iterate through corrections in
|
||||
// `TransformTypoExpr`.
|
||||
TransformCache.erase(TE);
|
||||
ExprResult AmbigRes = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous);
|
||||
|
||||
if (!AmbigRes.isInvalid() || IsAmbiguous) {
|
||||
SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream();
|
||||
SavedTransformCache.erase(TE);
|
||||
Res = ExprError();
|
||||
IsAmbiguous = true;
|
||||
break;
|
||||
}
|
||||
} while ((Next = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection()) &&
|
||||
Next.getEditDistance(false) == TC.getEditDistance(false));
|
||||
|
||||
if (IsAmbiguous)
|
||||
break;
|
||||
|
||||
AmbiguousTypoExprs.remove(TE);
|
||||
SemaRef.getTypoExprState(TE).Consumer->restoreSavedPosition();
|
||||
TransformCache[TE] = SavedTransformCache[TE];
|
||||
}
|
||||
TransformCache = std::move(SavedTransformCache);
|
||||
}
|
||||
|
||||
// Wipe away any newly created TypoExprs that we don't know about. Since we
|
||||
// clear any invalid TypoExprs in `CheckForRecursiveTypos`, this is only
|
||||
// possible if a `TypoExpr` is created during a transformation but then
|
||||
// fails before we can discover it.
|
||||
auto &SemaTypoExprs = SemaRef.TypoExprs;
|
||||
for (auto Iterator = SemaTypoExprs.begin(); Iterator != SemaTypoExprs.end();) {
|
||||
auto TE = *Iterator;
|
||||
auto FI = find(TypoExprs, TE);
|
||||
if (FI != TypoExprs.end()) {
|
||||
Iterator++;
|
||||
continue;
|
||||
}
|
||||
SemaRef.clearDelayedTypo(TE);
|
||||
Iterator = SemaTypoExprs.erase(Iterator);
|
||||
}
|
||||
SemaRef.TypoExprs = std::move(SavedTypoExprs);
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
public:
|
||||
TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref<ExprResult(Expr *)> Filter)
|
||||
: BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {}
|
||||
|
||||
ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc,
|
||||
MultiExprArg Args,
|
||||
SourceLocation RParenLoc,
|
||||
Expr *ExecConfig = nullptr) {
|
||||
auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args,
|
||||
RParenLoc, ExecConfig);
|
||||
if (auto *OE = dyn_cast<OverloadExpr>(Callee)) {
|
||||
if (Result.isUsable()) {
|
||||
Expr *ResultCall = Result.get();
|
||||
if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall))
|
||||
ResultCall = BE->getSubExpr();
|
||||
if (auto *CE = dyn_cast<CallExpr>(ResultCall))
|
||||
OverloadResolution[OE] = CE->getCallee();
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); }
|
||||
|
||||
ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); }
|
||||
|
||||
ExprResult Transform(Expr *E) {
|
||||
bool IsAmbiguous = false;
|
||||
ExprResult Res = RecursiveTransformLoop(E, IsAmbiguous);
|
||||
|
||||
if (!Res.isUsable())
|
||||
FindTypoExprs(TypoExprs).TraverseStmt(E);
|
||||
|
||||
EmitAllDiagnostics(IsAmbiguous);
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
ExprResult TransformTypoExpr(TypoExpr *E) {
|
||||
// If the TypoExpr hasn't been seen before, record it. Otherwise, return the
|
||||
// cached transformation result if there is one and the TypoExpr isn't the
|
||||
// first one that was encountered.
|
||||
auto &CacheEntry = TransformCache[E];
|
||||
if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) {
|
||||
return CacheEntry;
|
||||
}
|
||||
|
||||
auto &State = SemaRef.getTypoExprState(E);
|
||||
assert(State.Consumer && "Cannot transform a cleared TypoExpr");
|
||||
|
||||
// For the first TypoExpr and an uncached TypoExpr, find the next likely
|
||||
// typo correction and return it.
|
||||
while (TypoCorrection TC = State.Consumer->getNextCorrection()) {
|
||||
if (InitDecl && TC.getFoundDecl() == InitDecl)
|
||||
continue;
|
||||
// FIXME: If we would typo-correct to an invalid declaration, it's
|
||||
// probably best to just suppress all errors from this typo correction.
|
||||
ExprResult NE = State.RecoveryHandler ?
|
||||
State.RecoveryHandler(SemaRef, E, TC) :
|
||||
attemptRecovery(SemaRef, *State.Consumer, TC);
|
||||
if (!NE.isInvalid()) {
|
||||
// Check whether there may be a second viable correction with the same
|
||||
// edit distance; if so, remember this TypoExpr may have an ambiguous
|
||||
// correction so it can be more thoroughly vetted later.
|
||||
TypoCorrection Next;
|
||||
if ((Next = State.Consumer->peekNextCorrection()) &&
|
||||
Next.getEditDistance(false) == TC.getEditDistance(false)) {
|
||||
AmbiguousTypoExprs.insert(E);
|
||||
} else {
|
||||
AmbiguousTypoExprs.remove(E);
|
||||
}
|
||||
assert(!NE.isUnset() &&
|
||||
"Typo was transformed into a valid-but-null ExprResult");
|
||||
return CacheEntry = NE;
|
||||
}
|
||||
}
|
||||
return CacheEntry = ExprError();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl,
|
||||
bool RecoverUncorrectedTypos,
|
||||
llvm::function_ref<ExprResult(Expr *)> Filter) {
|
||||
// If the current evaluation context indicates there are uncorrected typos
|
||||
// and the current expression isn't guaranteed to not have typos, try to
|
||||
// resolve any TypoExpr nodes that might be in the expression.
|
||||
if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos &&
|
||||
(E->isTypeDependent() || E->isValueDependent() ||
|
||||
E->isInstantiationDependent())) {
|
||||
auto TyposResolved = DelayedTypos.size();
|
||||
auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E);
|
||||
TyposResolved -= DelayedTypos.size();
|
||||
if (Result.isInvalid() || Result.get() != E) {
|
||||
ExprEvalContexts.back().NumTypos -= TyposResolved;
|
||||
if (Result.isInvalid() && RecoverUncorrectedTypos) {
|
||||
struct TyposReplace : TreeTransform<TyposReplace> {
|
||||
TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {}
|
||||
ExprResult TransformTypoExpr(clang::TypoExpr *E) {
|
||||
return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(),
|
||||
E->getEndLoc(), {});
|
||||
}
|
||||
} TT(*this);
|
||||
return TT.TransformExpr(E);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
assert(TyposResolved == 0 && "Corrected typo but got same Expr back?");
|
||||
}
|
||||
return E;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
|
||||
bool DiscardedValue, bool IsConstexpr,
|
||||
bool IsTemplateArgument) {
|
||||
@ -8095,8 +7723,6 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
|
||||
DiagnoseUnusedExprResult(FullExpr.get(), diag::warn_unused_expr);
|
||||
}
|
||||
|
||||
FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr,
|
||||
/*RecoverUncorrectedTypos=*/true);
|
||||
if (FullExpr.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
|
||||
@ -650,64 +650,11 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Callback to only accept typo corrections that are either a ValueDecl or a
|
||||
// FunctionTemplateDecl and are declared in the current record or, for a C++
|
||||
// classes, one of its base classes.
|
||||
class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
|
||||
public:
|
||||
explicit RecordMemberExprValidatorCCC(QualType RTy)
|
||||
: Record(RTy->getAsRecordDecl()) {
|
||||
// Don't add bare keywords to the consumer since they will always fail
|
||||
// validation by virtue of not being associated with any decls.
|
||||
WantTypeSpecifiers = false;
|
||||
WantExpressionKeywords = false;
|
||||
WantCXXNamedCasts = false;
|
||||
WantFunctionLikeCasts = false;
|
||||
WantRemainingKeywords = false;
|
||||
}
|
||||
|
||||
bool ValidateCandidate(const TypoCorrection &candidate) override {
|
||||
NamedDecl *ND = candidate.getCorrectionDecl();
|
||||
// Don't accept candidates that cannot be member functions, constants,
|
||||
// variables, or templates.
|
||||
if (!ND || !(isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)))
|
||||
return false;
|
||||
|
||||
// Accept candidates that occur in the current record.
|
||||
if (Record->containsDecl(ND))
|
||||
return true;
|
||||
|
||||
if (const auto *RD = dyn_cast<CXXRecordDecl>(Record)) {
|
||||
// Accept candidates that occur in any of the current class' base classes.
|
||||
for (const auto &BS : RD->bases()) {
|
||||
if (const auto *BSTy = BS.getType()->getAs<RecordType>()) {
|
||||
if (BSTy->getDecl()->containsDecl(ND))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<CorrectionCandidateCallback> clone() override {
|
||||
return std::make_unique<RecordMemberExprValidatorCCC>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
const RecordDecl *const Record;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
|
||||
Expr *BaseExpr, QualType RTy,
|
||||
SourceLocation OpLoc, bool IsArrow,
|
||||
CXXScopeSpec &SS, bool HasTemplateArgs,
|
||||
SourceLocation TemplateKWLoc,
|
||||
TypoExpr *&TE) {
|
||||
SourceLocation TemplateKWLoc) {
|
||||
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
|
||||
if (!RTy->isDependentType() &&
|
||||
!SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
|
||||
@ -724,56 +671,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
|
||||
/*EnteringContext=*/false, TemplateKWLoc);
|
||||
|
||||
SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
|
||||
|
||||
if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
|
||||
return false;
|
||||
|
||||
DeclarationName Typo = R.getLookupName();
|
||||
SourceLocation TypoLoc = R.getNameLoc();
|
||||
// Recompute the lookup context.
|
||||
DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS)
|
||||
: SemaRef.computeDeclContext(RTy);
|
||||
|
||||
struct QueryState {
|
||||
Sema &SemaRef;
|
||||
DeclarationNameInfo NameInfo;
|
||||
Sema::LookupNameKind LookupKind;
|
||||
RedeclarationKind Redecl;
|
||||
};
|
||||
QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(),
|
||||
R.redeclarationKind()};
|
||||
RecordMemberExprValidatorCCC CCC(RTy);
|
||||
TE = SemaRef.CorrectTypoDelayed(
|
||||
R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, CCC,
|
||||
[=, &SemaRef](const TypoCorrection &TC) {
|
||||
if (TC) {
|
||||
assert(!TC.isKeyword() &&
|
||||
"Got a keyword as a correction for a member!");
|
||||
bool DroppedSpecifier =
|
||||
TC.WillReplaceSpecifier() &&
|
||||
Typo.getAsString() == TC.getAsString(SemaRef.getLangOpts());
|
||||
SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest)
|
||||
<< Typo << DC << DroppedSpecifier
|
||||
<< SS.getRange());
|
||||
} else {
|
||||
SemaRef.Diag(TypoLoc, diag::err_no_member)
|
||||
<< Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange);
|
||||
}
|
||||
},
|
||||
[=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable {
|
||||
LookupResult R(Q.SemaRef, Q.NameInfo, Q.LookupKind, Q.Redecl);
|
||||
R.clear(); // Ensure there's no decls lingering in the shared state.
|
||||
R.suppressDiagnostics();
|
||||
R.setLookupName(TC.getCorrection());
|
||||
for (NamedDecl *ND : TC)
|
||||
R.addDecl(ND);
|
||||
R.resolveKind();
|
||||
return SemaRef.BuildMemberReferenceExpr(
|
||||
BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(),
|
||||
nullptr, R, nullptr, nullptr);
|
||||
},
|
||||
CorrectTypoKind::ErrorRecovery, DC);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -793,15 +690,11 @@ ExprResult Sema::BuildMemberReferenceExpr(
|
||||
|
||||
// Implicit member accesses.
|
||||
if (!Base) {
|
||||
TypoExpr *TE = nullptr;
|
||||
QualType RecordTy = BaseType;
|
||||
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
|
||||
if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow,
|
||||
SS, TemplateArgs != nullptr, TemplateKWLoc,
|
||||
TE))
|
||||
SS, TemplateArgs != nullptr, TemplateKWLoc))
|
||||
return ExprError();
|
||||
if (TE)
|
||||
return TE;
|
||||
|
||||
// Explicit member accesses.
|
||||
} else {
|
||||
@ -1396,16 +1289,15 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
|
||||
|
||||
// Handle field access to simple records.
|
||||
if (BaseType->getAsRecordDecl()) {
|
||||
TypoExpr *TE = nullptr;
|
||||
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
|
||||
SS, HasTemplateArgs, TemplateKWLoc, TE))
|
||||
SS, HasTemplateArgs, TemplateKWLoc))
|
||||
return ExprError();
|
||||
|
||||
// Returning valid-but-null is how we indicate to the caller that
|
||||
// the lookup result was filled in. If typo correction was attempted and
|
||||
// failed, the lookup result will have been cleared--that combined with the
|
||||
// valid-but-null ExprResult will trigger the appropriate diagnostics.
|
||||
return ExprResult(TE);
|
||||
return ExprResult{};
|
||||
} else if (BaseType->isDependentType()) {
|
||||
R.setNotFoundInCurrentInstantiation();
|
||||
return ExprEmpty();
|
||||
|
||||
@ -5444,40 +5444,6 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
|
||||
return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure && !SecondBestTC);
|
||||
}
|
||||
|
||||
TypoExpr *Sema::CorrectTypoDelayed(
|
||||
const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind,
|
||||
Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC,
|
||||
TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode,
|
||||
DeclContext *MemberContext, bool EnteringContext,
|
||||
const ObjCObjectPointerType *OPT) {
|
||||
auto Consumer = makeTypoCorrectionConsumer(
|
||||
TypoName, LookupKind, S, SS, CCC, MemberContext, EnteringContext, OPT,
|
||||
Mode == CorrectTypoKind::ErrorRecovery);
|
||||
|
||||
// Give the external sema source a chance to correct the typo.
|
||||
TypoCorrection ExternalTypo;
|
||||
if (ExternalSource && Consumer) {
|
||||
ExternalTypo = ExternalSource->CorrectTypo(
|
||||
TypoName, LookupKind, S, SS, *Consumer->getCorrectionValidator(),
|
||||
MemberContext, EnteringContext, OPT);
|
||||
if (ExternalTypo)
|
||||
Consumer->addCorrection(ExternalTypo);
|
||||
}
|
||||
|
||||
if (!Consumer || Consumer->empty())
|
||||
return nullptr;
|
||||
|
||||
// Make sure the best edit distance (prior to adding any namespace qualifiers)
|
||||
// is not more that about a third of the length of the typo's identifier.
|
||||
unsigned ED = Consumer->getBestEditDistance(true);
|
||||
IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
|
||||
if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3)
|
||||
return nullptr;
|
||||
ExprEvalContexts.back().NumTypos++;
|
||||
return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC),
|
||||
TypoName.getLoc());
|
||||
}
|
||||
|
||||
void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
|
||||
if (!CDecl) return;
|
||||
|
||||
@ -5802,32 +5768,6 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
|
||||
Diag(Correction.getCorrectionRange().getBegin(), PD);
|
||||
}
|
||||
|
||||
TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
|
||||
TypoDiagnosticGenerator TDG,
|
||||
TypoRecoveryCallback TRC,
|
||||
SourceLocation TypoLoc) {
|
||||
assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer");
|
||||
auto TE = new (Context) TypoExpr(Context.DependentTy, TypoLoc);
|
||||
auto &State = DelayedTypos[TE];
|
||||
State.Consumer = std::move(TCC);
|
||||
State.DiagHandler = std::move(TDG);
|
||||
State.RecoveryHandler = std::move(TRC);
|
||||
if (TE)
|
||||
TypoExprs.push_back(TE);
|
||||
return TE;
|
||||
}
|
||||
|
||||
const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const {
|
||||
auto Entry = DelayedTypos.find(TE);
|
||||
assert(Entry != DelayedTypos.end() &&
|
||||
"Failed to get the state for a TypoExpr!");
|
||||
return Entry->second;
|
||||
}
|
||||
|
||||
void Sema::clearDelayedTypo(TypoExpr *TE) {
|
||||
DelayedTypos.erase(TE);
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) {
|
||||
DeclarationNameInfo Name(II, IILoc);
|
||||
LookupResult R(*this, Name, LookupAnyName,
|
||||
|
||||
@ -124,17 +124,12 @@ ExprResult SemaObjC::CheckObjCForCollectionOperand(SourceLocation forLoc,
|
||||
if (!collection)
|
||||
return ExprError();
|
||||
|
||||
ExprResult result = SemaRef.CorrectDelayedTyposInExpr(collection);
|
||||
if (!result.isUsable())
|
||||
return ExprError();
|
||||
collection = result.get();
|
||||
|
||||
// Bail out early if we've got a type-dependent expression.
|
||||
if (collection->isTypeDependent())
|
||||
return collection;
|
||||
|
||||
// Perform normal l-value conversion.
|
||||
result = SemaRef.DefaultFunctionArrayLvalueConversion(collection);
|
||||
ExprResult result = SemaRef.DefaultFunctionArrayLvalueConversion(collection);
|
||||
if (result.isInvalid())
|
||||
return ExprError();
|
||||
collection = result.get();
|
||||
|
||||
@ -14055,8 +14055,10 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(
|
||||
// specified and it, along with any default template arguments,
|
||||
// identifies a single function template specialization, then the
|
||||
// template-id is an lvalue for the function template specialization.
|
||||
FunctionTemplateDecl *FunctionTemplate
|
||||
= cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl());
|
||||
FunctionTemplateDecl *FunctionTemplate =
|
||||
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl());
|
||||
if (!FunctionTemplate)
|
||||
continue;
|
||||
|
||||
// C++ [over.over]p2:
|
||||
// If the name is a function template, template argument deduction is
|
||||
|
||||
@ -535,12 +535,7 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) {
|
||||
return ER;
|
||||
};
|
||||
|
||||
ExprResult Converted = CorrectDelayedTyposInExpr(
|
||||
Val, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false,
|
||||
CheckAndFinish);
|
||||
if (Converted.get() == Val.get())
|
||||
Converted = CheckAndFinish(Val.get());
|
||||
return Converted;
|
||||
return CheckAndFinish(Val.get());
|
||||
}
|
||||
|
||||
StmtResult
|
||||
@ -2344,7 +2339,7 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
|
||||
static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
|
||||
SourceLocation Loc, int DiagID) {
|
||||
if (Decl->getType()->isUndeducedType()) {
|
||||
ExprResult Res = SemaRef.CorrectDelayedTyposInExpr(Init);
|
||||
ExprResult Res = Init;
|
||||
if (!Res.isUsable()) {
|
||||
Decl->setInvalidDecl();
|
||||
return true;
|
||||
@ -3845,10 +3840,7 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
|
||||
StmtResult
|
||||
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
|
||||
Scope *CurScope) {
|
||||
// Correct typos, in case the containing function returns 'auto' and
|
||||
// RetValExp should determine the deduced type.
|
||||
ExprResult RetVal = CorrectDelayedTyposInExpr(
|
||||
RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true);
|
||||
ExprResult RetVal = RetValExp;
|
||||
if (RetVal.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
|
||||
@ -782,11 +782,10 @@ ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
|
||||
ExprResult Sema::BuildCXXAssumeExpr(Expr *Assumption,
|
||||
const IdentifierInfo *AttrName,
|
||||
SourceRange Range) {
|
||||
ExprResult Res = CorrectDelayedTyposInExpr(Assumption);
|
||||
if (Res.isInvalid())
|
||||
if (!Assumption)
|
||||
return ExprError();
|
||||
|
||||
Res = CheckPlaceholderExpr(Res.get());
|
||||
ExprResult Res = CheckPlaceholderExpr(Assumption);
|
||||
if (Res.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
|
||||
@ -741,7 +741,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
|
||||
if (!Pattern->containsUnexpandedParameterPack()) {
|
||||
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
||||
<< Pattern->getSourceRange();
|
||||
CorrectDelayedTyposInExpr(Pattern);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
@ -1201,11 +1200,9 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
|
||||
SourceLocation RSquareLoc) {
|
||||
bool isParameterPack = ::isParameterPack(PackExpression);
|
||||
if (!isParameterPack) {
|
||||
if (!PackExpression->containsErrors()) {
|
||||
CorrectDelayedTyposInExpr(IndexExpr);
|
||||
if (!PackExpression->containsErrors())
|
||||
Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack)
|
||||
<< PackExpression;
|
||||
}
|
||||
return ExprError();
|
||||
}
|
||||
ExprResult Res =
|
||||
@ -1403,11 +1400,6 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
|
||||
CheckFoldOperand(*this, LHS);
|
||||
CheckFoldOperand(*this, RHS);
|
||||
|
||||
auto DiscardOperands = [&] {
|
||||
CorrectDelayedTyposInExpr(LHS);
|
||||
CorrectDelayedTyposInExpr(RHS);
|
||||
};
|
||||
|
||||
// [expr.prim.fold]p3:
|
||||
// In a binary fold, op1 and op2 shall be the same fold-operator, and
|
||||
// either e1 shall contain an unexpanded parameter pack or e2 shall contain
|
||||
@ -1415,7 +1407,6 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
|
||||
if (LHS && RHS &&
|
||||
LHS->containsUnexpandedParameterPack() ==
|
||||
RHS->containsUnexpandedParameterPack()) {
|
||||
DiscardOperands();
|
||||
return Diag(EllipsisLoc,
|
||||
LHS->containsUnexpandedParameterPack()
|
||||
? diag::err_fold_expression_packs_both_sides
|
||||
@ -1430,7 +1421,6 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
|
||||
Expr *Pack = LHS ? LHS : RHS;
|
||||
assert(Pack && "fold expression with neither LHS nor RHS");
|
||||
if (!Pack->containsUnexpandedParameterPack()) {
|
||||
DiscardOperands();
|
||||
return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
||||
<< Pack->getSourceRange();
|
||||
}
|
||||
|
||||
@ -13121,12 +13121,6 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) {
|
||||
return E;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformTypoExpr(TypoExpr *E) {
|
||||
return E;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
ExprResult TreeTransform<Derived>::TransformRecoveryExpr(RecoveryExpr *E) {
|
||||
llvm::SmallVector<Expr *, 8> Children;
|
||||
|
||||
@ -2310,10 +2310,6 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
|
||||
E->setIsUnique(Record.readInt());
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitTypoExpr(TypoExpr *E) {
|
||||
llvm_unreachable("Cannot read TypoExpr nodes");
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitRecoveryExpr(RecoveryExpr *E) {
|
||||
VisitExpr(E);
|
||||
unsigned NumArgs = Record.readInt();
|
||||
|
||||
@ -2314,12 +2314,6 @@ void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
|
||||
Code = serialization::EXPR_OPAQUE_VALUE;
|
||||
}
|
||||
|
||||
void ASTStmtWriter::VisitTypoExpr(TypoExpr *E) {
|
||||
VisitExpr(E);
|
||||
// TODO: Figure out sane writer behavior for a TypoExpr, if necessary
|
||||
llvm_unreachable("Cannot write TypoExpr nodes");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CUDA Expressions and Statements.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -1732,7 +1732,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
||||
case Stmt::ExpressionTraitExprClass:
|
||||
case Stmt::UnresolvedLookupExprClass:
|
||||
case Stmt::UnresolvedMemberExprClass:
|
||||
case Stmt::TypoExprClass:
|
||||
case Stmt::RecoveryExprClass:
|
||||
case Stmt::CXXNoexceptExprClass:
|
||||
case Stmt::PackExpansionExprClass:
|
||||
|
||||
@ -910,7 +910,8 @@ namespace CompoundLiterals {
|
||||
constexpr int f2(int *x =(int[]){1,2,3}) {
|
||||
return x[0];
|
||||
}
|
||||
constexpr int g = f2(); // Should evaluate to 1?
|
||||
// Should evaluate to 1?
|
||||
constexpr int g = f2(); // #g_decl
|
||||
static_assert(g == 1, "");
|
||||
|
||||
// This example should be rejected because the lifetime of the compound
|
||||
@ -1347,7 +1348,10 @@ namespace NTTP {
|
||||
namespace UnaryOpError {
|
||||
constexpr int foo() {
|
||||
int f = 0;
|
||||
++g; // both-error {{use of undeclared identifier 'g'}}
|
||||
++g; // both-error {{use of undeclared identifier 'g'}} \
|
||||
both-error {{cannot assign to variable 'g' with const-qualified type 'const int'}} \
|
||||
both-note@#g_decl {{'CompoundLiterals::g' declared here}} \
|
||||
both-note@#g_decl {{variable 'g' declared const here}}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,13 +23,6 @@ int postfix_inc = a++;
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int'
|
||||
int unary_address = &(a + 1);
|
||||
|
||||
// CHECK: VarDecl {{.*}} ternary 'int' cinit
|
||||
// CHECK-NEXT: `-ConditionalOperator {{.*}}
|
||||
// CHECK-NEXT: |-DeclRefExpr {{.*}} 'a'
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}}
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'a'
|
||||
int ternary = a ? undef : a;
|
||||
|
||||
void test1() {
|
||||
// CHECK: `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'a' 'const int'
|
||||
@ -91,12 +84,6 @@ void test3() {
|
||||
// CHECK-NEXT: | `-DeclRefExpr {{.*}} '__builtin_classify_type'
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
||||
(*__builtin_classify_type)(1);
|
||||
|
||||
extern void ext();
|
||||
// CHECK: CallExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-DeclRefExpr {{.*}} 'ext'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
ext(undef_var);
|
||||
}
|
||||
|
||||
// Verify no crash.
|
||||
@ -110,23 +97,6 @@ void test4() {
|
||||
};
|
||||
}
|
||||
|
||||
// Verify no crash
|
||||
void test5_GH62711() {
|
||||
// CHECK: VAArgExpr {{.*}} 'int' contains-errors
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
if (__builtin_va_arg(undef, int) << 1);
|
||||
}
|
||||
|
||||
void test6_GH50244() {
|
||||
double array[16];
|
||||
// CHECK: UnaryExprOrTypeTraitExpr {{.*}} 'unsigned long' contains-errors sizeof
|
||||
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-DeclRefExpr {{.*}} 'int ()'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
sizeof array / sizeof foo(undef);
|
||||
}
|
||||
|
||||
// No crash on DeclRefExpr that refers to ValueDecl with invalid initializers.
|
||||
void test7() {
|
||||
int b[] = {""()};
|
||||
|
||||
@ -9,28 +9,6 @@ int some_func(int *);
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 123
|
||||
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
|
||||
int invalid_call = some_func(123);
|
||||
void test_invalid_call_1(int s) {
|
||||
// CHECK: CallExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:13>
|
||||
// CHECK-NEXT: `-BinaryOperator {{.*}}
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}}
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} <col:28> 'int' 1
|
||||
some_func(undef1, undef2+1);
|
||||
|
||||
// CHECK: BinaryOperator {{.*}} '<dependent type>' contains-errors '='
|
||||
// CHECK-NEXT: |-DeclRefExpr {{.*}} 's'
|
||||
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
s = some_func(undef1);
|
||||
|
||||
// CHECK: VarDecl {{.*}} var 'int'
|
||||
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
int var = some_func(undef1);
|
||||
}
|
||||
|
||||
int some_func2(int a, int b);
|
||||
void test_invalid_call_2() {
|
||||
@ -63,22 +41,6 @@ int ambig_func(float);
|
||||
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
|
||||
int ambig_call = ambig_func(123);
|
||||
|
||||
// CHECK: VarDecl {{.*}} unresolved_call1
|
||||
// CHECK-NEXT:`-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'bar'
|
||||
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
|
||||
int unresolved_call1 = bar();
|
||||
|
||||
// CHECK: VarDecl {{.*}} unresolved_call2
|
||||
// CHECK-NEXT:`-CallExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'bar'
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} 'baz'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'qux'
|
||||
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
|
||||
int unresolved_call2 = bar(baz(), qux());
|
||||
|
||||
constexpr int a = 10;
|
||||
|
||||
// CHECK: VarDecl {{.*}} postfix_inc
|
||||
@ -177,11 +139,6 @@ void test2(Foo2 f) {
|
||||
f.overload(1);
|
||||
}
|
||||
|
||||
// CHECK: |-AlignedAttr {{.*}} alignas
|
||||
// CHECK-NEXT:| `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT:| `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
struct alignas(invalid()) Aligned {};
|
||||
|
||||
auto f();
|
||||
int f(double);
|
||||
// CHECK: VarDecl {{.*}} unknown_type_call 'int'
|
||||
@ -203,16 +160,6 @@ void InvalidInitalizer(int x) {
|
||||
// CHECK-NEXT: `-InitListExpr
|
||||
// CHECK-NEDT: `-DeclRefExpr {{.*}} 'x'
|
||||
Bar a3{x};
|
||||
// CHECK: `-VarDecl {{.*}} a4 'Bar'
|
||||
// CHECK-NEXT: `-ParenListExpr {{.*}} 'NULL TYPE' contains-errors
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
Bar a4(invalid());
|
||||
// CHECK: `-VarDecl {{.*}} a5 'Bar'
|
||||
// CHECK-NEXT: `-InitListExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
Bar a5{invalid()};
|
||||
|
||||
// CHECK: `-VarDecl {{.*}} b1 'Bar'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
@ -231,51 +178,11 @@ void InvalidInitalizer(int x) {
|
||||
// CHECK-NEXT: `-InitListExpr {{.*}} 'void'
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int'
|
||||
Bar b4 = Bar{x};
|
||||
// CHECK: `-VarDecl {{.*}} b5 'Bar'
|
||||
// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
Bar b5 = Bar(invalid());
|
||||
// CHECK: `-VarDecl {{.*}} b6 'Bar'
|
||||
// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar'
|
||||
// CHECK-NEXT: `-InitListExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
Bar b6 = Bar{invalid()};
|
||||
|
||||
// CHECK: RecoveryExpr {{.*}} 'Bar' contains-errors
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
||||
Bar(1);
|
||||
|
||||
// CHECK: `-VarDecl {{.*}} var1
|
||||
// CHECK-NEXT: `-BinaryOperator {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
||||
int var1 = undef + 1;
|
||||
}
|
||||
void InitializerForAuto() {
|
||||
// CHECK: `-VarDecl {{.*}} invalid a 'auto'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
auto a = invalid();
|
||||
|
||||
// CHECK: `-VarDecl {{.*}} invalid b 'auto'
|
||||
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
|
||||
auto b = some_func(invalid());
|
||||
|
||||
decltype(ned);
|
||||
// very bad initailizer: there is an unresolved typo expr internally, we just
|
||||
// drop it.
|
||||
// CHECK: `-VarDecl {{.*}} invalid unresolved_typo 'auto'
|
||||
auto unresolved_typo = gned.*[] {};
|
||||
}
|
||||
|
||||
// Verified that the generated call operator is invalid.
|
||||
// CHECK: |-CXXMethodDecl {{.*}} invalid operator() 'auto () const -> auto'
|
||||
using Escape = decltype([] { return undef(); }());
|
||||
|
||||
// CHECK: VarDecl {{.*}} NoCrashOnInvalidInitList
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors lvalue
|
||||
@ -301,56 +208,8 @@ void ValueCategory() {
|
||||
xvalue(); // call to a function (rvalue reference return type) yields an xvalue.
|
||||
}
|
||||
|
||||
void InvalidCondition() {
|
||||
// CHECK: IfStmt {{.*}}
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:7, col:15> '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} <col:7>
|
||||
if (invalid()) {}
|
||||
|
||||
// CHECK: WhileStmt {{.*}}
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:10, col:18> '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} <col:10>
|
||||
while (invalid()) {}
|
||||
|
||||
// CHECK: SwitchStmt {{.*}}
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} <col:10>
|
||||
switch(invalid()) {
|
||||
case 1:
|
||||
break;
|
||||
}
|
||||
// FIXME: figure out why the type of ConditionalOperator is not int.
|
||||
// CHECK: ConditionalOperator {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}}
|
||||
// CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2
|
||||
invalid() ? 1 : 2;
|
||||
}
|
||||
|
||||
void CtorInitializer() {
|
||||
struct S{int m};
|
||||
class MemberInit {
|
||||
int x, y, z;
|
||||
S s;
|
||||
MemberInit() : x(invalid), y(invalid, invalid), z(invalid()), s(1,2) {}
|
||||
// CHECK: CXXConstructorDecl {{.*}} MemberInit 'void ()'
|
||||
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'x' 'int'
|
||||
// CHECK-NEXT: | `-ParenListExpr
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'y' 'int'
|
||||
// CHECK-NEXT: | `-ParenListExpr
|
||||
// CHECK-NEXT: | |-RecoveryExpr {{.*}} '<dependent type>'
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'z' 'int'
|
||||
// CHECK-NEXT: | `-ParenListExpr
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} '<overloaded function type>'
|
||||
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 's' 'S'
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'S' contains-errors
|
||||
// CHECK-NEXT: | |-IntegerLiteral {{.*}} 1
|
||||
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 2
|
||||
};
|
||||
class BaseInit : S {
|
||||
BaseInit(float) : S("no match") {}
|
||||
// CHECK: CXXConstructorDecl {{.*}} BaseInit 'void (float)'
|
||||
@ -358,13 +217,6 @@ void CtorInitializer() {
|
||||
// CHECK-NEXT: |-CXXCtorInitializer 'S'
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'S'
|
||||
// CHECK-NEXT: | `-StringLiteral
|
||||
|
||||
BaseInit(double) : S(invalid) {}
|
||||
// CHECK: CXXConstructorDecl {{.*}} BaseInit 'void (double)'
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: |-CXXCtorInitializer 'S'
|
||||
// CHECK-NEXT: | `-ParenListExpr
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
};
|
||||
class DelegatingInit {
|
||||
DelegatingInit(float) : DelegatingInit("no match") {}
|
||||
@ -373,13 +225,6 @@ void CtorInitializer() {
|
||||
// CHECK-NEXT: |-CXXCtorInitializer 'DelegatingInit'
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'DelegatingInit'
|
||||
// CHECK-NEXT: | `-StringLiteral
|
||||
|
||||
DelegatingInit(double) : DelegatingInit(invalid) {}
|
||||
// CHECK: CXXConstructorDecl {{.*}} DelegatingInit 'void (double)'
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: |-CXXCtorInitializer 'DelegatingInit'
|
||||
// CHECK-NEXT: | `-ParenListExpr
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
};
|
||||
}
|
||||
|
||||
@ -423,65 +268,6 @@ void returnInitListFromVoid() {
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 8
|
||||
}
|
||||
|
||||
void RecoveryExprForInvalidDecls(Unknown InvalidDecl) {
|
||||
InvalidDecl + 1;
|
||||
// CHECK: BinaryOperator {{.*}}
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>'
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'InvalidDecl' 'int'
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
||||
InvalidDecl();
|
||||
// CHECK: CallExpr {{.*}}
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
|
||||
}
|
||||
|
||||
void InitializerOfInvalidDecl() {
|
||||
int ValidDecl;
|
||||
Unkown InvalidDecl = ValidDecl;
|
||||
// CHECK: VarDecl {{.*}} invalid InvalidDecl
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'ValidDecl'
|
||||
|
||||
Unknown InvalidDeclWithInvalidInit = Invalid;
|
||||
// CHECK: VarDecl {{.*}} invalid InvalidDeclWithInvalidInit
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NOT: `-TypoExpr
|
||||
}
|
||||
|
||||
void RecoverToAnInvalidDecl() {
|
||||
Unknown* foo; // invalid decl
|
||||
goo; // the typo was correct to the invalid foo.
|
||||
// Verify that RecoveryExpr has an inner DeclRefExpr.
|
||||
// CHECK: RecoveryExpr {{.*}} '<dependent type>' contains-errors lvalue
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
|
||||
}
|
||||
|
||||
void RecoveryToDoWhileStmtCond() {
|
||||
// CHECK: FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
|
||||
// CHECK: `-DoStmt {{.*}}
|
||||
// CHECK-NEXT: |-CompoundStmt {{.*}}
|
||||
// CHECK-NEXT: `-BinaryOperator {{.*}} '<dependent type>' contains-errors '<'
|
||||
// CHECK-NEXT: |-BinaryOperator {{.*}} '<dependent type>' contains-errors '+'
|
||||
// CHECK-NEXT: | |-RecoveryExpr {{.*}} '<dependent type>' contains-errors lvalue
|
||||
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 10
|
||||
do {} while (some_invalid_val + 1 < 10);
|
||||
}
|
||||
|
||||
void RecoveryForStmtCond() {
|
||||
// CHECK:FunctionDecl {{.*}} RecoveryForStmtCond
|
||||
// CHECK-NEXT:`-CompoundStmt {{.*}}
|
||||
// CHECK-NEXT: `-ForStmt {{.*}}
|
||||
// CHECK-NEXT: |-DeclStmt {{.*}}
|
||||
// CHECK-NEXT: | `-VarDecl {{.*}}
|
||||
// CHECK-NEXT: | `-IntegerLiteral {{.*}} <col:16> 'int' 0
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-RecoveryExpr {{.*}} 'bool' contains-errors
|
||||
// CHECK-NEXT: |-UnaryOperator {{.*}} 'int' lvalue prefix '++'
|
||||
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'i' 'int'
|
||||
// CHECK-NEXT: `-CompoundStmt {{.*}}
|
||||
for (int i = 0; i < invalid; ++i) {}
|
||||
}
|
||||
|
||||
// Fix crash issue https://github.com/llvm/llvm-project/issues/112560.
|
||||
// Make sure clang compiles the following code without crashing:
|
||||
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -fblocks -ast-dump %s | FileCheck -strict-whitespace %s
|
||||
|
||||
@interface Foo
|
||||
- (void)method:(int)n;
|
||||
@end
|
||||
|
||||
void k(Foo *foo) {
|
||||
// CHECK: ObjCMessageExpr {{.*}} 'void' contains-errors
|
||||
// CHECK-CHECK: |-ImplicitCastExpr {{.*}} 'Foo *' <LValueToRValue>
|
||||
// CHECK-CHECK: | `-DeclRefExpr {{.*}} 'foo'
|
||||
// CHECK-CHECK: `-RecoveryExpr {{.*}}
|
||||
[foo method:undef];
|
||||
|
||||
// CHECK: ImplicitCastExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo'
|
||||
foo.undef;
|
||||
}
|
||||
|
||||
// CHECK: |-VarDecl {{.*}} 'int (^)()' cinit
|
||||
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type> (^)(void)' contains-errors lvalue
|
||||
// CHECK-NEXT: | `-BlockExpr {{.*}} '<dependent type> (^)(void)'
|
||||
// CHECK-NEXT: | `-BlockDecl {{.*}} invalid
|
||||
int (^gh63863)() = ^() {
|
||||
return undef;
|
||||
};
|
||||
|
||||
// CHECK: `-BlockExpr {{.*}} 'int (^)(int, int)'
|
||||
// CHECK-NEXT: `-BlockDecl {{.*}} invalid
|
||||
int (^gh64005)(int, int) = ^(int, undefined b) {
|
||||
return 1;
|
||||
};
|
||||
@ -702,8 +702,7 @@ namespace cwg141 { // cwg141: 3.1
|
||||
// cxx98-error@#cwg141-a {{lookup of 'S' in member access expression is ambiguous; using member of 'struct A'}}
|
||||
// cxx98-note@#cwg141-A-S {{lookup in the object type 'struct A' refers here}}
|
||||
// cxx98-note@#cwg141-S {{lookup from the current scope refers here}}
|
||||
// expected-error@#cwg141-a {{no member named 'n' in 'cwg141::A::S<int>'; did you mean '::cwg141::S<int>::n'?}}
|
||||
// expected-note@#cwg141-S {{'::cwg141::S<int>::n' declared here}}
|
||||
// expected-error@#cwg141-a {{no member named 'n' in 'cwg141::A::S<int>'}}
|
||||
// FIXME: we issue a useful diagnostic first, then some bogus ones.
|
||||
b.f<int>();
|
||||
// expected-error@-1 {{no member named 'f' in 'cwg141::B'}}
|
||||
|
||||
@ -220,7 +220,6 @@ int x = cwg2640_a\N{abc});
|
||||
int y = cwg2640_a\N{LOTUS});
|
||||
// expected-error@-1 {{character <U+1FAB7> not allowed in an identifier}}
|
||||
// expected-error@-2 {{use of undeclared identifier 'cwg2640_a🪷'}}
|
||||
// expected-error@-3 {{extraneous ')' before ';'}}
|
||||
} // namespace cwg2640
|
||||
|
||||
// cwg2642: na
|
||||
|
||||
@ -51,7 +51,7 @@ void use_from_module_impl() {
|
||||
(void)external_linkage_var;
|
||||
(void)module_linkage_var;
|
||||
|
||||
(void)internal_linkage_class{}; // expected-error {{use of undeclared identifier 'internal_linkage_class'}} //expected-error{{}}
|
||||
(void)internal_linkage_class{}; // expected-error {{use of undeclared identifier 'internal_linkage_class'}} // expected-note@* {{}}
|
||||
(void)internal_linkage_var; // expected-error {{use of undeclared identifier 'internal_linkage_var'}}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ void use_from_module_impl() {
|
||||
internal_linkage_fn(); // expected-error {{use of undeclared identifier 'internal_linkage_fn'}}
|
||||
(void)external_linkage_class{};
|
||||
(void)module_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} // expected-note@* {{}}
|
||||
(void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}}
|
||||
(void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} // expected-note@* {{}}
|
||||
(void)external_linkage_var;
|
||||
(void)module_linkage_var; // expected-error {{undeclared identifier}}
|
||||
(void)internal_linkage_var; // expected-error {{undeclared identifier}}
|
||||
|
||||
@ -1,137 +0,0 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// RUN: cp %s %t
|
||||
// RUN: not %clang_cc1 -fixit -x c++ %t
|
||||
// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
|
||||
// RUN: grep test_string %t
|
||||
|
||||
namespace std {
|
||||
template<typename T> class basic_string { // expected-note 3{{'basic_string' declared here}}
|
||||
public:
|
||||
int find(const char *substr); // expected-note{{'find' declared here}}
|
||||
static const int npos = -1; // expected-note{{'npos' declared here}}
|
||||
};
|
||||
|
||||
typedef basic_string<char> string; // expected-note 2{{'string' declared here}}
|
||||
}
|
||||
|
||||
namespace otherstd { // expected-note 2{{'otherstd' declared here}} \
|
||||
// expected-note{{namespace 'otherstd' defined here}}
|
||||
using namespace std;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
other_std::strng str1; // expected-error{{use of undeclared identifier 'other_std'; did you mean 'otherstd'?}} \
|
||||
// expected-error{{no type named 'strng' in namespace 'otherstd'; did you mean 'string'?}}
|
||||
tring str2; // expected-error{{unknown type name 'tring'; did you mean 'string'?}}
|
||||
|
||||
::other_std::string str3; // expected-error{{no member named 'other_std' in the global namespace; did you mean 'otherstd'?}}
|
||||
|
||||
float area(float radius, // expected-note{{'radius' declared here}}
|
||||
float pi) {
|
||||
return radious * pi; // expected-error{{did you mean 'radius'?}}
|
||||
}
|
||||
|
||||
using namespace othestd; // expected-error{{no namespace named 'othestd'; did you mean 'otherstd'?}}
|
||||
namespace blargh = otherstd; // expected-note 3{{namespace 'blargh' defined here}}
|
||||
using namespace ::blarg; // expected-error{{no namespace named 'blarg' in the global namespace; did you mean 'blargh'?}}
|
||||
|
||||
namespace wibble = blarg; // expected-error{{no namespace named 'blarg'; did you mean 'blargh'?}}
|
||||
namespace wobble = ::blarg; // expected-error{{no namespace named 'blarg' in the global namespace; did you mean 'blargh'?}}
|
||||
|
||||
bool test_string(std::string s) {
|
||||
basc_string<char> b1; // expected-error{{no template named 'basc_string'; did you mean 'basic_string'?}}
|
||||
std::basic_sting<char> b2; // expected-error{{no template named 'basic_sting' in namespace 'std'; did you mean 'basic_string'?}}
|
||||
(void)b1;
|
||||
(void)b2;
|
||||
return s.fnd("hello") // expected-error{{no member named 'fnd' in 'std::basic_string<char>'; did you mean 'find'?}}
|
||||
== std::string::pos; // expected-error{{no member named 'pos' in 'std::basic_string<char>'; did you mean 'npos'?}}
|
||||
}
|
||||
|
||||
struct Base { };
|
||||
struct Derived : public Base { // expected-note{{base class 'Base' specified here}}
|
||||
int member; // expected-note 3{{'member' declared here}}
|
||||
|
||||
Derived() : base(), // expected-error{{initializer 'base' does not name a non-static data member or base class; did you mean the base class 'Base'?}}
|
||||
ember() { } // expected-error{{initializer 'ember' does not name a non-static data member or base class; did you mean the member 'member'?}}
|
||||
|
||||
int getMember() const {
|
||||
return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}}
|
||||
}
|
||||
|
||||
int &getMember();
|
||||
};
|
||||
|
||||
int &Derived::getMember() {
|
||||
return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}}
|
||||
}
|
||||
|
||||
typedef int Integer; // expected-note{{'Integer' declared here}}
|
||||
int global_value; // expected-note{{'global_value' declared here}}
|
||||
|
||||
int foo() {
|
||||
integer * i = 0; // expected-error{{unknown type name 'integer'; did you mean 'Integer'?}}
|
||||
unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
|
||||
return *i + *ptr + global_val; // expected-error{{use of undeclared identifier 'global_val'; did you mean 'global_value'?}}
|
||||
}
|
||||
|
||||
namespace nonstd {
|
||||
typedef std::basic_string<char> yarn; // expected-note 2 {{'nonstd::yarn' declared here}}
|
||||
int narf; // expected-note{{'nonstd::narf' declared here}}
|
||||
}
|
||||
|
||||
yarn str4; // expected-error{{unknown type name 'yarn'; did you mean 'nonstd::yarn'?}}
|
||||
wibble::yarn str5; // expected-error{{no type named 'yarn' in namespace 'otherstd'; did you mean 'nonstd::yarn'?}}
|
||||
|
||||
namespace another {
|
||||
template<typename T> class wide_string {}; // expected-note {{'another::wide_string' declared here}}
|
||||
}
|
||||
int poit() {
|
||||
nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean simply 'basic_string'?}}
|
||||
nonstd::wide_string<char> str2; // expected-error{{no template named 'wide_string' in namespace 'nonstd'; did you mean 'another::wide_string'?}}
|
||||
return wibble::narf; // expected-error{{no member named 'narf' in namespace 'otherstd'; did you mean 'nonstd::narf'?}}
|
||||
}
|
||||
|
||||
namespace check_bool {
|
||||
void f() {
|
||||
Bool b; // expected-error{{use of undeclared identifier 'Bool'; did you mean 'bool'?}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace outr {
|
||||
}
|
||||
namespace outer {
|
||||
namespace inner { // expected-note{{'outer::inner' declared here}} \
|
||||
// expected-note{{namespace 'outer::inner' defined here}} \
|
||||
// expected-note{{'inner' declared here}}
|
||||
int i;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace outr::inner; // expected-error{{no namespace named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}}
|
||||
|
||||
void func() {
|
||||
outr::inner::i = 3; // expected-error{{no member named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}}
|
||||
outer::innr::i = 4; // expected-error{{no member named 'innr' in namespace 'outer'; did you mean 'inner'?}}
|
||||
}
|
||||
|
||||
struct base {
|
||||
};
|
||||
struct derived : base {
|
||||
int i;
|
||||
};
|
||||
|
||||
void func2() {
|
||||
derived d;
|
||||
// FIXME: we should offer a fix here. We do if the 'i' is misspelled, but we don't do name qualification changes
|
||||
// to replace base::i with derived::i as we would for other qualified name misspellings.
|
||||
// d.base::i = 3;
|
||||
}
|
||||
|
||||
class A {
|
||||
void bar(int);
|
||||
};
|
||||
void bar(int, int); // expected-note{{'::bar' declared here}}
|
||||
void A::bar(int x) {
|
||||
bar(x, 5); // expected-error{{too many arguments to function call, expected 1, have 2; did you mean '::bar'?}}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
void f() {
|
||||
auto foo = bar;
|
||||
switch(foo) {
|
||||
case x:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// RUN: not %clang_cc1 -fsyntax-only -fno-recovery-ast -code-completion-at=%s:4:10 %s | FileCheck %s -allow-empty
|
||||
// CHECK-NOT: COMPLETION: foo
|
||||
@ -1,27 +1,12 @@
|
||||
// RUN: c-index-test -test-load-source all -fspell-checking %s 2> %t
|
||||
// RUN: c-index-test -test-load-source all -fspell-checking %s 2> %t
|
||||
// RUN: FileCheck %s < %t
|
||||
struct X {
|
||||
int wibble;
|
||||
};
|
||||
|
||||
#define MACRO(X) X
|
||||
|
||||
void f(struct X *x) {
|
||||
// CHECK: error: no member named 'wobble' in 'struct X'; did you mean 'wibble'?
|
||||
// CHECK: FIX-IT: Replace [13:12 - 13:18] with "wibble"
|
||||
// CHECK: note: 'wibble' declared here
|
||||
MACRO(x->wobble = 17);
|
||||
// CHECK: error: no member named 'wabble' in 'struct X'; did you mean 'wibble'?
|
||||
// CHECK: FIX-IT: Replace [17:6 - 17:12] with "wibble"
|
||||
// CHECK: note: 'wibble' declared here
|
||||
x->wabble = 17;
|
||||
}
|
||||
|
||||
int printf(const char *restrict, ...);
|
||||
|
||||
void f2() {
|
||||
unsigned long index;
|
||||
// CHECK: warning: format specifies type 'int' but the argument has type 'unsigned long'
|
||||
// CHECK: FIX-IT: Replace [26:17 - 26:19] with "%lu"
|
||||
// CHECK: FIX-IT: Replace [11:17 - 11:19] with "%lu"
|
||||
MACRO(printf("%d", index));
|
||||
}
|
||||
|
||||
@ -27,13 +27,13 @@
|
||||
// no-warning@* {{ignoring '-fno-raw-string-literals'}}
|
||||
|
||||
void f() {
|
||||
(void) R"foo()foo"; // unsupported-error {{use of undeclared identifier 'R'}} cxx-unsupported-error {{expected ';' after expression}}
|
||||
(void) LR"foo()foo"; // unsupported-error {{use of undeclared identifier 'LR'}} cxx-unsupported-error {{expected ';' after expression}}
|
||||
(void) R"foo()foo"; // unsupported-error {{use of undeclared identifier 'R'}}
|
||||
(void) LR"foo()foo"; // unsupported-error {{use of undeclared identifier 'LR'}}
|
||||
|
||||
#ifdef UNICODE
|
||||
(void) uR"foo()foo"; // unsupported-error {{use of undeclared identifier 'uR'}} cxx-unsupported-error {{expected ';' after expression}}
|
||||
(void) u8R"foo()foo"; // unsupported-error {{use of undeclared identifier 'u8R'}} cxx-unsupported-error {{expected ';' after expression}}
|
||||
(void) UR"foo()foo"; // unsupported-error {{use of undeclared identifier 'UR'}} cxx-unsupported-error {{expected ';' after expression}}
|
||||
(void) uR"foo()foo"; // unsupported-error {{use of undeclared identifier 'uR'}}
|
||||
(void) u8R"foo()foo"; // unsupported-error {{use of undeclared identifier 'u8R'}}
|
||||
(void) UR"foo()foo"; // unsupported-error {{use of undeclared identifier 'UR'}}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -7,11 +7,9 @@
|
||||
void foo(void) {
|
||||
XYZLogEvent(xyzRiskyCloseOpenParam, xyzRiskyCloseOpenParam); // expected-error {{call to undeclared function 'XYZLogEvent'; ISO C99 and later do not support implicit function declarations}} \
|
||||
expected-error {{declaration of 'XYZLogEvent' must be imported}} \
|
||||
expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}} \
|
||||
expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}}
|
||||
}
|
||||
|
||||
// expected-note@Inputs/diagnose-missing-import/a.h:5 {{declaration here is not visible}}
|
||||
// expected-note@Inputs/diagnose-missing-import/a.h:5 {{declaration here is not visible}}
|
||||
// expected-note@Inputs/diagnose-missing-import/a.h:6 {{declaration here is not visible}}
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ const int var;
|
||||
#pragma omp end declare variant
|
||||
#pragma omp begin declare variant match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('<invalid>'); score ignored}}
|
||||
#pragma omp end declare variant
|
||||
#pragma omp begin declare variant match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('<recovery-expr>()'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp begin declare variant match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('<invalid>'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp end declare variant
|
||||
#pragma omp begin declare variant match(device={kind(score(2 gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('2'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp end declare variant
|
||||
|
||||
@ -69,7 +69,7 @@ class Class2 : public Class1<T> {
|
||||
#pragma omp declare reduction(fun77 : long : omp_out += omp_in) initializer(omp_priv Class2 < int > ()) // expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare reduction(fun8 : long : omp_out += omp_in) initializer(omp_priv 23) // expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare reduction(fun88 : long : omp_out += omp_in) initializer(omp_priv 23)) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
|
||||
#pragma omp declare reduction(fun9 : long : omp_out += omp_priv) initializer(omp_in = 23) // expected-error {{use of undeclared identifier 'omp_priv'; did you mean 'omp_in'?}} expected-note {{'omp_in' declared here}}
|
||||
#pragma omp declare reduction(fun9 : long : omp_out += omp_priv) initializer(omp_in = 23) // expected-error {{use of undeclared identifier 'omp_priv'}}
|
||||
#pragma omp declare reduction(fun10 : long : omp_out += omp_in) initializer(omp_priv = 23)
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -11,7 +11,7 @@ int foo(void);
|
||||
#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}}
|
||||
#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foo // expected-error {{expected ')'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} omp50-error {{expected 'match' clause on}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}}
|
||||
#pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(foo) xxx // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
@ -42,7 +42,7 @@ int foo(void);
|
||||
#pragma omp declare variant(foo) match(device={kind(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foo) match(device={kind()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}}
|
||||
#pragma omp declare variant(foo) match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('<invalid>'); score ignored}}
|
||||
#pragma omp declare variant(foo) match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('<recovery-expr>()'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foo) match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('<invalid>'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foo) match(device={kind(score(2 gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('2'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foo) match(device={kind(score(foo()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('foo()'); score ignored}} expected-warning {{'ibm' is not a valid context property for the context selector 'kind' and the context set 'device'; property ignored}} expected-note {{try 'match(implementation={vendor(ibm)})'}} expected-note {{the ignored property spans until here}}
|
||||
#pragma omp declare variant(foo) match(device={kind(score(5): host), kind(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('5'); score ignored}} expected-warning {{the context selector 'kind' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'kind' used here}} expected-note {{the ignored selector spans until here}}
|
||||
@ -56,7 +56,7 @@ int foo(void);
|
||||
#pragma omp declare variant(foo) match(target_device={device_num}) // expected-warning {{the context selector 'device_num' in context set 'target_device' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}}
|
||||
#pragma omp declare variant(foo) match(target_device={device_num()}) // expected-error {{expected expression}}
|
||||
#pragma omp declare variant(foo) match(target_device={device_num(-1)}) // expected-error {{argument to 'device_num' clause must be a non-negative integer value}}
|
||||
#pragma omp declare variant(foo) match(target_device={device_num(abc)}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'abc'}}
|
||||
#pragma omp declare variant(foo) match(target_device={device_num(abc)}) // expected-error {{use of undeclared identifier 'abc'}}
|
||||
int bar(void);
|
||||
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ T foofoo();
|
||||
#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}}
|
||||
#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foo // expected-error {{expected ')'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}}
|
||||
#pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(foofoo <int>) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(foofoo <int>) xxx // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
@ -57,7 +57,7 @@ int bar();
|
||||
#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}}
|
||||
#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(foofoo <T> // expected-error {{expected ')'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} expected-note {{to match this '('}}
|
||||
#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}}
|
||||
#pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(foofoo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
#pragma omp declare variant(foofoo <T>) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
|
||||
|
||||
@ -113,9 +113,11 @@ int main(int argc, char **argv) {
|
||||
// Check parsing with two modifiers.
|
||||
// lt51-warning@+1 {{missing ':' after ) - ignoring}}
|
||||
#pragma omp target update to(mapper(id), present: s)
|
||||
// lt51-error@+3 {{use of undeclared identifier 'present'}}
|
||||
// lt51-error@+2 {{use of undeclared identifier 'id'}}
|
||||
// lt51-error@+1 {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
|
||||
// lt51-error@+5 {{use of undeclared identifier 'present'}}
|
||||
// lt51-error@+4 {{use of undeclared identifier 'id'}}
|
||||
// lt51-error@+3 {{expected ',' or ')' in 'to' clause}}
|
||||
// lt51-error@+2 {{expected ')'}}
|
||||
// lt51-note@+1 {{to match this '('}}
|
||||
#pragma omp target update to(present, mapper(id): s)
|
||||
// lt51-warning@+1 {{missing ':' after ) - ignoring}}
|
||||
#pragma omp target update to(mapper(id) present: s)
|
||||
@ -141,10 +143,9 @@ int main(int argc, char **argv) {
|
||||
#pragma omp target update to(present,,: s)
|
||||
// lt51-warning@+1 {{missing ':' after ) - ignoring}}
|
||||
#pragma omp target update to(mapper(id), present,: s)
|
||||
// lt51-error@+4 {{use of undeclared identifier 'present'}}
|
||||
// lt51-error@+3 {{use of undeclared identifier 'id'}}
|
||||
// lt51-error@+2 {{expected expression}}
|
||||
// lt51-error@+1 {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
|
||||
// lt51-error@+3 {{use of undeclared identifier 'present'}}
|
||||
// lt51-error@+2 {{use of undeclared identifier 'id'}}
|
||||
// lt51-error@+1 {{expected expression}}
|
||||
#pragma omp target update to(present, mapper(id),: s)
|
||||
|
||||
#pragma omp target update from(m) allocate(m) // expected-error {{unexpected OpenMP clause 'allocate' in directive '#pragma omp target update'}}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-unknown-linux-gnu -verify=expected,cxx2c,post2b -fcxx-exceptions
|
||||
// RUN: not %clang_cc1 -std=c++17 %s -triple x86_64-unknown-linux-gnu -emit-llvm-only -fcxx-exceptions
|
||||
|
||||
struct S { int a, b, c; };
|
||||
struct S { int a, b, c; }; // expected-note 2 {{'S::a' declared here}}
|
||||
|
||||
// A simple-declaration can be a decompsition declaration.
|
||||
namespace SimpleDecl {
|
||||
@ -32,7 +32,7 @@ namespace ForRangeDecl {
|
||||
namespace OtherDecl {
|
||||
// A parameter-declaration is not a simple-declaration.
|
||||
// This parses as an array declaration.
|
||||
void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error {{'a'}}
|
||||
void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error 1+{{'a'}}
|
||||
|
||||
void g() {
|
||||
// A condition is allowed as a Clang extension.
|
||||
@ -46,7 +46,7 @@ namespace OtherDecl {
|
||||
|
||||
// An exception-declaration is not a simple-declaration.
|
||||
try {}
|
||||
catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error {{'a'}}
|
||||
catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error 1+{{'a'}}
|
||||
}
|
||||
|
||||
// A member-declaration is not a simple-declaration.
|
||||
|
||||
@ -37,14 +37,14 @@ template<int ...N> int bad12() { return (... N); } // expected-error {{expected
|
||||
|
||||
template<typename ...T> void as_operand_of_cast(int a, T ...t) {
|
||||
return
|
||||
(int)(a + ... + undeclared_junk) + // expected-error {{undeclared}} expected-error {{does not contain any unexpanded}}
|
||||
(int)(a + ... + undeclared_junk) + // expected-error {{undeclared}}
|
||||
(int)(t + ... + undeclared_junk) + // expected-error {{undeclared}}
|
||||
(int)(... + undeclared_junk) + // expected-error {{undeclared}} expected-error {{does not contain any unexpanded}}
|
||||
(int)(... + undeclared_junk) + // expected-error {{undeclared}}
|
||||
(int)(undeclared_junk + ...) + // expected-error {{undeclared}}
|
||||
(int)(a + ...) + // expected-error {{does not contain any unexpanded}}
|
||||
(int)(a, ...) + // expected-error {{does not contain any unexpanded}}
|
||||
(int)(..., a) + // expected-error {{does not contain any unexpanded}}
|
||||
(int)(a, ..., undeclared_junk) + // expected-error {{undeclared}} expected-error {{does not contain any unexpanded}}
|
||||
(int)(a, ..., undeclared_junk) + // expected-error {{undeclared}}
|
||||
(int)(t, ...) +
|
||||
(int)(..., t) +
|
||||
(int)(t, ..., a);
|
||||
|
||||
@ -69,7 +69,8 @@ template <typename... T>
|
||||
requires( ); // expected-error {{expected expression}}
|
||||
struct SS {
|
||||
void f( ) {
|
||||
(*p).~T...[](); // expected-error {{use of undeclared identifier 'p'}}
|
||||
(*p).~T...[](); // expected-error {{use of undeclared identifier 'p'}} \
|
||||
expected-error {{undeclared identifier 'T' in destructor name}}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -21,6 +21,5 @@ MyList * el;
|
||||
|
||||
|
||||
static int test7(id keys) {
|
||||
for (id key; in keys) ; // expected-error {{use of undeclared identifier 'in'}} \
|
||||
// expected-error {{expected ';' in 'for' statement specifier}}
|
||||
for (id key; in keys) ; // expected-error {{use of undeclared identifier 'in'}}
|
||||
}
|
||||
|
||||
@ -39,23 +39,17 @@ void atomic_types_test(void) {
|
||||
// expected-error@-11 {{use of undeclared identifier 'atomic_ulong'}}
|
||||
// expected-error@-11 {{use of undeclared identifier 'atomic_double'}}
|
||||
#if defined(LANG_VER_OK)
|
||||
// expected-error@-15 {{expected ';' after expression}}
|
||||
// expected-error@-16 {{use of undeclared identifier 'l'}}
|
||||
// expected-error@-16 {{expected ';' after expression}}
|
||||
// expected-error@-17 {{use of undeclared identifier 'ul'}}
|
||||
#endif
|
||||
#if !defined(LANG_VER_OK) || defined(__SPIR64__)
|
||||
// expected-error@-18 {{use of undeclared identifier 'atomic_size_t'}}
|
||||
// expected-error@-16 {{use of undeclared identifier 'atomic_ptrdiff_t'}}
|
||||
// expected-error@-14 {{use of undeclared identifier 'atomic_size_t'}}
|
||||
// expected-error@-12 {{use of undeclared identifier 'atomic_ptrdiff_t'}}
|
||||
#if !defined(LANG_VER_OK)
|
||||
// expected-error@-20 {{use of undeclared identifier 'atomic_intptr_t'}}
|
||||
// expected-error@-20 {{use of undeclared identifier 'atomic_uintptr_t'}}
|
||||
// expected-error@-16 {{use of undeclared identifier 'atomic_intptr_t'}}
|
||||
// expected-error@-16 {{use of undeclared identifier 'atomic_uintptr_t'}}
|
||||
#else
|
||||
// expected-error@-24 {{expected ';' after expression}}
|
||||
// expected-error@-25 {{use of undeclared identifier 's'}}
|
||||
// expected-error@-25 {{unknown type name 'atomic_intptr_t'; did you mean 'atomic_int'?}}
|
||||
// expected-error@-19 {{unknown type name 'atomic_intptr_t'; did you mean 'atomic_int'?}}
|
||||
// expected-note@* {{'atomic_int' declared here}}
|
||||
// expected-error@-26 {{unknown type name 'atomic_uintptr_t'; did you mean 'atomic_uint'?}}
|
||||
// expected-error@-20 {{unknown type name 'atomic_uintptr_t'; did you mean 'atomic_uint'?}}
|
||||
// expected-note@* {{'atomic_uint' declared here}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -11,7 +11,7 @@ float test2241[2] = {
|
||||
static void f (char * (*g) (char **, int), char **p, ...) {
|
||||
char *s;
|
||||
va_list v; // expected-error {{identifier}}
|
||||
s = g (p, __builtin_va_arg(v, int)); // expected-error {{identifier}}
|
||||
s = g (p, __builtin_va_arg(v, int)); // expected-error {{identifier}} expected-error {{extraneous ')' before ';'}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -104,7 +104,7 @@ void test9(int x) { // expected-note {{'x' declared here}}
|
||||
expected-error {{expected expression}}
|
||||
8:: x; // expected-error {{expected ';' after expression}} \
|
||||
expected-error {{no member named 'x' in the global namespace; did you mean simply 'x'?}} \
|
||||
expected-warning {{expression result unused}}
|
||||
expected-warning 2 {{expression result unused}}
|
||||
9:: :y; // expected-error {{expected ';' after expression}} \
|
||||
expected-error {{expected unqualified-id}} \
|
||||
expected-warning {{expression result unused}}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
namespace c { double xxx; } // expected-note{{'c::xxx' declared here}}
|
||||
namespace c { double xxx; }
|
||||
namespace d { float xxx; }
|
||||
namespace z { namespace xxx {} }
|
||||
|
||||
void crash() {
|
||||
switch (xxx) {} // expected-error{{use of undeclared identifier 'xxx'; did you mean }}
|
||||
switch (xxx) {} // expected-error{{use of undeclared identifier 'xxx'}}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// RUN: %clang_cc1 %s -verify -fopenacc
|
||||
|
||||
namespace NS {
|
||||
static char* NSArray;// expected-note{{declared here}}
|
||||
static int NSInt;// expected-note 2{{declared here}}
|
||||
static char* NSArray; // expected-note {{'NS::NSArray' declared here}}
|
||||
static int NSInt; // expected-note 2 {{'NS::NSInt' declared here}}
|
||||
}
|
||||
char *getArrayPtr();
|
||||
template<typename T, int I>
|
||||
@ -21,17 +21,17 @@ void func() {
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// expected-error@+1{{use of undeclared identifier 'NSArray'; did you mean 'NS::NSArray'}}
|
||||
// expected-error@+1{{use of undeclared identifier 'NSArray'}}
|
||||
#pragma acc cache(NSArray[NS::NSInt : NS::NSInt])
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// expected-error@+1{{use of undeclared identifier 'NSInt'; did you mean 'NS::NSInt'}}
|
||||
// expected-error@+1{{use of undeclared identifier 'NSInt'}}
|
||||
#pragma acc cache(NS::NSArray[NSInt : NS::NSInt])
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// expected-error@+1{{use of undeclared identifier 'NSInt'; did you mean 'NS::NSInt'}}
|
||||
// expected-error@+1{{use of undeclared identifier 'NSInt'}}
|
||||
#pragma acc cache(NS::NSArray[NS::NSInt : NSInt])
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,9 +347,7 @@ void SelfUpdate() {
|
||||
#pragma acc update host(s) self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+3{{use of undeclared identifier 'zero'}}
|
||||
// expected-error@+2{{expected ','}}
|
||||
// expected-error@+1{{expected expression}}
|
||||
// expected-error@+1{{use of undeclared identifier 'zero'}}
|
||||
#pragma acc update self(zero : s.array[s.value : 5], s.value), if_present
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
@ -453,8 +451,6 @@ void VarListClauses() {
|
||||
#pragma acc parallel copy(always, alwaysin, always: HasMem.MemArr[3:]) self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+3{{use of undeclared identifier 'always'}}
|
||||
// expected-error@+2{{use of undeclared identifier 'alwaysin'}}
|
||||
// expected-error@+1{{use of undeclared identifier 'always'}}
|
||||
#pragma acc parallel copy(always, alwaysin, always, HasMem.MemArr[3:]) self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
@ -591,8 +587,7 @@ void VarListClauses() {
|
||||
#pragma acc serial copyout(zero : s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'zero'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'zero'}}
|
||||
#pragma acc serial copyout(zero s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
@ -608,8 +603,7 @@ void VarListClauses() {
|
||||
#pragma acc serial copyout(invalid:s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'invalid'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'invalid'}}
|
||||
#pragma acc serial copyout(invalid s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
@ -657,8 +651,7 @@ void VarListClauses() {
|
||||
#pragma acc serial create(zero : s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'zero'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'zero'}}
|
||||
#pragma acc serial create(zero s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
@ -674,8 +667,7 @@ void VarListClauses() {
|
||||
#pragma acc serial create(invalid:s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'invalid'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'invalid'}}
|
||||
#pragma acc serial create(invalid s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
@ -700,8 +692,7 @@ void VarListClauses() {
|
||||
#pragma acc serial copyin(readonly : s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'readonly'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'readonly'}}
|
||||
#pragma acc serial copyin(readonly s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
@ -717,8 +708,7 @@ void VarListClauses() {
|
||||
#pragma acc serial copyin(invalid:s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'invalid'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'invalid'}}
|
||||
#pragma acc serial copyin(invalid s.array[s.value : 5], s.value), self
|
||||
for(int i = 0; i < 5;++i) {}
|
||||
|
||||
|
||||
@ -18,13 +18,13 @@ namespace NS {
|
||||
#pragma acc routine(NS::foo) seq
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}}
|
||||
// expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}}
|
||||
// expected-error@+1{{OpenACC routine name 'templ' names a set of overloads}}
|
||||
#pragma acc routine(templ) seq
|
||||
// expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}}
|
||||
#pragma acc routine(NS::templ) seq
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}}
|
||||
// expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}}
|
||||
// expected-error@+1{{OpenACC routine name 'templ<int>' names a set of overloads}}
|
||||
#pragma acc routine(templ<int>) seq
|
||||
// expected-error@+1{{OpenACC routine name 'NS::templ<int>' names a set of overloads}}
|
||||
#pragma acc routine(NS::templ<int>) seq
|
||||
|
||||
@ -85,19 +85,16 @@ void func() {
|
||||
#pragma acc parallel wait (devnum: i + j:queues:) clause-list
|
||||
{}
|
||||
|
||||
// expected-error@+4{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+3{{expected ','}}
|
||||
// expected-error@+3{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+2{{expected ')'}}
|
||||
// expected-note@+1{{to match this '('}}
|
||||
#pragma acc parallel wait (queues:devnum: i + j
|
||||
{}
|
||||
|
||||
// expected-error@+2{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'devnum'}}
|
||||
#pragma acc parallel wait (queues:devnum: i + j)
|
||||
{}
|
||||
|
||||
// expected-error@+3{{expected ','}}
|
||||
// expected-error@+2{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+1{{invalid OpenACC clause 'clause'}}
|
||||
#pragma acc parallel wait (queues:devnum: i + j) clause-list
|
||||
|
||||
@ -68,18 +68,15 @@ void func() {
|
||||
// expected-error@+1{{invalid OpenACC clause 'clause'}}
|
||||
#pragma acc wait (devnum: i + j:queues:) clause-list
|
||||
|
||||
// expected-error@+4{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+3{{expected ','}}
|
||||
// expected-error@+3{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+2{{expected ')'}}
|
||||
// expected-note@+1{{to match this '('}}
|
||||
#pragma acc wait (queues:devnum: i + j
|
||||
|
||||
// expected-error@+2{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+1{{expected ','}}
|
||||
// expected-error@+1{{use of undeclared identifier 'devnum'}}
|
||||
#pragma acc wait (queues:devnum: i + j)
|
||||
|
||||
// expected-error@+3{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+2{{expected ','}}
|
||||
// expected-error@+2{{use of undeclared identifier 'devnum'}}
|
||||
// expected-error@+1{{invalid OpenACC clause 'clause'}}
|
||||
#pragma acc wait (queues:devnum: i + j) clause-list
|
||||
|
||||
|
||||
@ -5,9 +5,9 @@ struct spinlock_t {
|
||||
} audit_skb_queue;
|
||||
|
||||
void fn1(void) {
|
||||
audit_skb_queue = (lock); // expected-error {{use of undeclared identifier 'lock'; did you mean 'long'?}}
|
||||
} // expected-error@-1 {{assigning to 'struct spinlock_t' from incompatible type '<overloaded function type>'}}
|
||||
audit_skb_queue = (lock); // expected-error {{use of undeclared identifier 'lock'}}
|
||||
}
|
||||
|
||||
void fn2(void) {
|
||||
audit_skb_queue + (lock); // expected-error {{use of undeclared identifier 'lock'; did you mean 'long'?}}
|
||||
} // expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}}
|
||||
audit_skb_queue + (lock); // expected-error {{use of undeclared identifier 'lock'}}
|
||||
}
|
||||
|
||||
@ -17,5 +17,4 @@ void a(void) {
|
||||
|
||||
check(__builtin_fpclassify(0,0,0,0,0, (invalid))); // expected-error{{use of undeclared identifier 'invalid'}}
|
||||
check(__builtin_fpclassify(0,0,0,0,0, (inf))); // expected-error{{use of undeclared identifier 'inf'}}
|
||||
// expected-error@-1{{reference to overloaded function could not be resolved}}
|
||||
}
|
||||
|
||||
18
clang/test/Sema/c23-delayed-typo-correction-crashes.c
Normal file
18
clang/test/Sema/c23-delayed-typo-correction-crashes.c
Normal file
@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
|
||||
|
||||
void GH139913(...);
|
||||
void GH139913_test() {
|
||||
GH139913(CONCAT(foo, )); // expected-error {{use of undeclared identifier 'CONCAT'}} \
|
||||
expected-error {{use of undeclared identifier 'foo'}} \
|
||||
expected-error {{expected expression}}
|
||||
}
|
||||
|
||||
struct GH137867 {
|
||||
char value;
|
||||
};
|
||||
void GH137867_test() {
|
||||
_Atomic(struct GH137867) t;
|
||||
while (!atomic_load(&t.value)->value) // expected-error {{use of undeclared identifier 'atomic_load'}} \
|
||||
expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
|
||||
;
|
||||
}
|
||||
18
clang/test/Sema/delayed-typo-correction-crashes.c
Normal file
18
clang/test/Sema/delayed-typo-correction-crashes.c
Normal file
@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -fblocks -ffixed-point -verify %s
|
||||
|
||||
void GH137860_test(void) {
|
||||
struct S {
|
||||
char h;
|
||||
};
|
||||
_Atomic struct S s = { .h = UINT8_MIN }; // expected-error {{use of undeclared identifier 'UINT8_MIN'}}
|
||||
__c11_atomic_fetch_add(&s.h, UINT8_MIN); // expected-error {{use of undeclared identifier 'UINT8_MIN'}} \
|
||||
expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
|
||||
}
|
||||
|
||||
int (^GH69470) (int i, int j) = ^(int i, int j)
|
||||
{ return i / j; }/ j; // expected-error {{use of undeclared identifier 'j'}}
|
||||
|
||||
void GH69874(void) {
|
||||
*a = (a_struct){0}; // expected-error {{use of undeclared identifier 'a'}} \
|
||||
expected-error {{use of undeclared identifier 'a_struct'}}
|
||||
}
|
||||
@ -20,10 +20,12 @@ class Z {
|
||||
// Should be able to evaluate sizeof without crashing.
|
||||
static_assert(sizeof(Z) == 1, "No valid members");
|
||||
|
||||
constexpr int N = undef; // expected-error {{use of undeclared identifier}}
|
||||
constexpr int N = undef; // expected-error {{use of undeclared identifier}} \
|
||||
expected-note {{declared here}}
|
||||
template<int a>
|
||||
class ABC {};
|
||||
class T {
|
||||
ABC<N> abc;
|
||||
ABC<N> abc; // expected-error {{non-type template argument is not a constant expression}} \
|
||||
expected-note {{initializer of 'N' is unknown}}
|
||||
};
|
||||
static_assert(sizeof(T) == 1, "No valid members");
|
||||
|
||||
@ -18,12 +18,12 @@ void testAmbiguousNoSuggestions()
|
||||
|
||||
namespace MultipleCorrectionsButNotAmbiguous
|
||||
{
|
||||
int PrefixType_Name(int value); // expected-note {{'PrefixType_Name' declared here}}
|
||||
int PrefixType_Name(int value);
|
||||
int PrefixType_MIN();
|
||||
int PrefixType_MAX();
|
||||
};
|
||||
|
||||
int testMultipleCorrectionsButNotAmbiguous() {
|
||||
int val = MultipleCorrectionsButNotAmbiguous::PrefixType_Enum(0); // expected-error {{no member named 'PrefixType_Enum' in namespace 'MultipleCorrectionsButNotAmbiguous'; did you mean 'PrefixType_Name'?}}
|
||||
int val = MultipleCorrectionsButNotAmbiguous::PrefixType_Enum(0); // expected-error {{no member named 'PrefixType_Enum' in namespace 'MultipleCorrectionsButNotAmbiguous'}}
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -2,16 +2,15 @@
|
||||
|
||||
// PR50797
|
||||
struct a {
|
||||
int xxx; // expected-note {{'xxx' declared here}}
|
||||
int xxx;
|
||||
};
|
||||
|
||||
int g_107;
|
||||
int g_108;
|
||||
int g_109;
|
||||
|
||||
struct a g_999; // expected-note 4{{'g_999' declared here}}
|
||||
struct a g_999;
|
||||
|
||||
void b(void) { (g_910.xxx = g_910.xxx); } //expected-error 2{{use of undeclared identifier 'g_910'; did you mean 'g_999'}}
|
||||
void b(void) { (g_910.xxx = g_910.xxx); } //expected-error 2{{use of undeclared identifier 'g_910'}}
|
||||
|
||||
void c(void) { (g_910.xxx = g_910.xxx1); } //expected-error 2{{use of undeclared identifier 'g_910'; did you mean 'g_999'}} \
|
||||
expected-error {{no member named 'xxx1' in 'struct a'; did you mean 'xxx'}}
|
||||
void c(void) { (g_910.xxx = g_910.xxx1); } //expected-error 2{{use of undeclared identifier 'g_910'}}
|
||||
|
||||
@ -8,10 +8,12 @@ struct rdar38642201 {
|
||||
|
||||
void rdar38642201_callee(int x, int y);
|
||||
void rdar38642201_caller() {
|
||||
struct rdar38642201 structVar;
|
||||
struct rdar38642201 structVar; //expected-note 2{{'structVar' declared here}}
|
||||
rdar38642201_callee(
|
||||
structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}}
|
||||
structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}}
|
||||
structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} \
|
||||
expected-error{{no member named 'fieldName1' in 'rdar38642201'}}
|
||||
structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} \
|
||||
expected-error{{no member named 'fieldName2' in 'rdar38642201'}}
|
||||
}
|
||||
|
||||
// Similar reproducer.
|
||||
@ -20,7 +22,7 @@ public:
|
||||
int minut() const = delete;
|
||||
int hour() const = delete;
|
||||
|
||||
int longit() const; //expected-note{{'longit' declared here}}
|
||||
int longit() const;
|
||||
int latit() const;
|
||||
};
|
||||
|
||||
@ -35,6 +37,6 @@ int Foo(const B &b) {
|
||||
}
|
||||
|
||||
int Bar(const B &b) {
|
||||
return b.depar().longitude() + //expected-error{{no member named 'longitude' in 'A'; did you mean 'longit'?}}
|
||||
return b.depar().longitude() + //expected-error{{no member named 'longitude' in 'A'}}
|
||||
b.depar().latitude(); //expected-error{{no member named 'latitude' in 'A'}}
|
||||
}
|
||||
|
||||
@ -8,13 +8,13 @@
|
||||
class DeepClass
|
||||
{
|
||||
public:
|
||||
void trigger() const; // expected-note {{'trigger' declared here}}
|
||||
void trigger() const;
|
||||
};
|
||||
|
||||
class Y
|
||||
{
|
||||
public:
|
||||
const DeepClass& getX() const { return m_deepInstance; } // expected-note {{'getX' declared here}}
|
||||
const DeepClass& getX() const { return m_deepInstance; }
|
||||
private:
|
||||
DeepClass m_deepInstance;
|
||||
int m_n;
|
||||
@ -23,7 +23,7 @@ private:
|
||||
class Z
|
||||
{
|
||||
public:
|
||||
const Y& getY0() const { return m_y0; } // expected-note {{'getY0' declared here}}
|
||||
const Y& getY0() const { return m_y0; }
|
||||
const Y& getActiveY() const { return m_y0; }
|
||||
|
||||
private:
|
||||
@ -35,9 +35,9 @@ Z z_obj;
|
||||
|
||||
void testMultipleCorrections()
|
||||
{
|
||||
z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'; did you mean 'getY0'}}
|
||||
getM(). // expected-error {{no member named 'getM' in 'Y'; did you mean 'getX'}}
|
||||
triggee(); // expected-error {{no member named 'triggee' in 'DeepClass'; did you mean 'trigger'}}
|
||||
z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'}}
|
||||
getM().
|
||||
triggee();
|
||||
}
|
||||
|
||||
void testNoCorrections()
|
||||
@ -53,19 +53,19 @@ struct A {
|
||||
C get_me_a_C();
|
||||
};
|
||||
struct B {
|
||||
D get_me_a_D(); // expected-note {{'get_me_a_D' declared here}}
|
||||
D get_me_a_D();
|
||||
};
|
||||
class Scope {
|
||||
public:
|
||||
A make_an_A();
|
||||
B make_a_B(); // expected-note {{'make_a_B' declared here}}
|
||||
B make_a_B();
|
||||
};
|
||||
|
||||
Scope scope_obj;
|
||||
|
||||
int testDiscardedCorrections() {
|
||||
return scope_obj.make_an_E(). // expected-error {{no member named 'make_an_E' in 'Scope'; did you mean 'make_a_B'}}
|
||||
get_me_a_Z().value; // expected-error {{no member named 'get_me_a_Z' in 'B'; did you mean 'get_me_a_D'}}
|
||||
return scope_obj.make_an_E(). // expected-error {{no member named 'make_an_E' in 'Scope'}}
|
||||
get_me_a_Z().value;
|
||||
}
|
||||
|
||||
class AmbiguousHelper {
|
||||
@ -120,13 +120,13 @@ int testDeepAmbiguity() {
|
||||
}
|
||||
|
||||
struct Dog {
|
||||
int age; //expected-note{{'age' declared here}}
|
||||
int size; //expected-note{{'size' declared here}}
|
||||
int age;
|
||||
int size;
|
||||
};
|
||||
|
||||
int from_dog_years(int DogYears, int DogSize);
|
||||
int get_dog_years() {
|
||||
struct Dog doggo;
|
||||
return from_dog_years(doggo.agee, //expected-error{{no member named 'agee' in 'Dog'; did you mean 'age'}}
|
||||
doggo.sizee); //expected-error{{no member named 'sizee' in 'Dog'; did you mean 'size'}}
|
||||
return from_dog_years(doggo.agee, //expected-error{{no member named 'agee' in 'Dog'}}
|
||||
doggo.sizee); //expected-error{{no member named 'sizee' in 'Dog'}}
|
||||
}
|
||||
|
||||
@ -50,10 +50,12 @@ void fn1(void) {
|
||||
cabs(errij); // expected-error {{use of undeclared identifier 'errij'}}
|
||||
}
|
||||
|
||||
extern long afunction(int);
|
||||
extern long afunction(int); // expected-note {{'afunction' declared here}} \
|
||||
expected-note {{passing argument to parameter here}}
|
||||
void fn2(void) {
|
||||
f(THIS_IS_AN_ERROR, // expected-error {{use of undeclared identifier 'THIS_IS_AN_ERROR'}}
|
||||
afunction(afunction_)); // expected-error {{use of undeclared identifier 'afunction_'}}
|
||||
afunction(afunction_)); // expected-error {{use of undeclared identifier 'afunction_'}} \
|
||||
expected-error {{incompatible pointer to integer conversion passing 'long (int)' to parameter of type 'int'}}
|
||||
}
|
||||
|
||||
int d = X ? d : L; // expected-error 2 {{use of undeclared identifier}}
|
||||
@ -94,22 +96,24 @@ struct rdar38642201 {
|
||||
|
||||
void rdar38642201_callee(int x, int y);
|
||||
void rdar38642201_caller(void) {
|
||||
struct rdar38642201 structVar;
|
||||
struct rdar38642201 structVar; // expected-note 2{{'structVar' declared here}}
|
||||
rdar38642201_callee(
|
||||
structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}}
|
||||
structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}}
|
||||
structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} \
|
||||
expected-error{{no member named 'fieldName1' in 'struct rdar38642201'}}
|
||||
structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} \
|
||||
expected-error{{no member named 'fieldName2' in 'struct rdar38642201'}}
|
||||
}
|
||||
|
||||
void PR40286_g(int x, int y);
|
||||
void PR40286_h(int x, int y, int z);
|
||||
void PR40286_1(int the_value) {
|
||||
PR40286_g(the_walue); // expected-error {{use of undeclared identifier 'the_walue'}}
|
||||
void PR40286_1(int the_value) { // expected-note {{'the_value' declared here}}
|
||||
PR40286_g(the_walue, 0); // expected-error {{use of undeclared identifier 'the_walue'}}
|
||||
}
|
||||
void PR40286_2(int the_value) {
|
||||
PR40286_h(the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'}}
|
||||
void PR40286_2(int the_value) { // expected-note {{'the_value' declared here}}
|
||||
PR40286_h(the_value, the_walue, 0); // expected-error {{use of undeclared identifier 'the_walue'}}
|
||||
}
|
||||
void PR40286_3(int the_value) {
|
||||
PR40286_h(the_walue); // expected-error {{use of undeclared identifier 'the_walue'}}
|
||||
void PR40286_3(int the_value) { // expected-note {{'the_value' declared here}}
|
||||
PR40286_h(the_walue, 0, 0); // expected-error {{use of undeclared identifier 'the_walue'}}
|
||||
}
|
||||
void PR40286_4(int the_value) { // expected-note {{'the_value' declared here}}
|
||||
PR40286_h(the_value, the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'; did you mean 'the_value'?}}
|
||||
|
||||
@ -47,23 +47,22 @@ class wrapped_ptr {
|
||||
public:
|
||||
wrapped_ptr(T* ptr) : ptr_(ptr) {}
|
||||
T* operator->() { return ptr_; }
|
||||
void Check(); // expected-note {{'Check' declared here}}
|
||||
void Check();
|
||||
private:
|
||||
T *ptr_;
|
||||
};
|
||||
|
||||
class Worker {
|
||||
public:
|
||||
void DoSomething(); // expected-note {{'DoSomething' declared here}}
|
||||
void DoSomething();
|
||||
void Chuck();
|
||||
};
|
||||
|
||||
void test() {
|
||||
wrapped_ptr<Worker> worker(new Worker);
|
||||
worker.DoSomething(); // expected-error {{no member named 'DoSomething' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'; did you mean to use '->' instead of '.'?}}
|
||||
worker.DoSamething(); // expected-error {{no member named 'DoSamething' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'; did you mean to use '->' instead of '.'?}} \
|
||||
// expected-error {{no member named 'DoSamething' in 'arrow_suggest::Worker'; did you mean 'DoSomething'?}}
|
||||
worker.Chuck(); // expected-error {{no member named 'Chuck' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'; did you mean 'Check'?}}
|
||||
worker.DoSamething(); // expected-error {{no member named 'DoSamething' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'}}
|
||||
worker.Chuck(); // expected-error {{no member named 'Chuck' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'}}
|
||||
}
|
||||
|
||||
} // namespace arrow_suggest
|
||||
|
||||
@ -1888,10 +1888,11 @@ namespace PR15884 {
|
||||
}
|
||||
|
||||
namespace AfterError {
|
||||
constexpr int error() {
|
||||
constexpr int error() { // pre-cxx23-error {{no return statement in constexpr function}}
|
||||
return foobar; // expected-error {{undeclared identifier}}
|
||||
}
|
||||
constexpr int k = error(); // expected-error {{constexpr variable 'k' must be initialized by a constant expression}}
|
||||
} // cxx23-note {{control reached end of constexpr function}}
|
||||
constexpr int k = error(); // cxx23-error {{constexpr variable 'k' must be initialized by a constant expression}} \
|
||||
cxx23-note {{in call to 'error()'}}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
@ -458,7 +458,7 @@ namespace PR18234 {
|
||||
#endif
|
||||
} a;
|
||||
A::S s = a; // expected-error {{no viable conversion from 'struct A' to 'A::S'}}
|
||||
A::E e = a;
|
||||
A::E e = a; // expected-note {{'e' declared here}}
|
||||
bool k1 = e == A::e; // expected-error {{no member named 'e'}}
|
||||
bool k2 = e.n == 0;
|
||||
}
|
||||
|
||||
@ -8,19 +8,16 @@
|
||||
// RUN: not %clang_cc1 -std=c++20 -fsyntax-only %s -fcxx-exceptions -fexceptions -Wunused-result 2>&1 | FileCheck %s
|
||||
|
||||
void no_coroutine_traits_bad_arg_await() {
|
||||
co_await a; // expected-error {{include <coroutine>}}
|
||||
// expected-error@-1 {{use of undeclared identifier 'a'}}
|
||||
co_await a; // expected-error {{use of undeclared identifier 'a'}}
|
||||
}
|
||||
|
||||
void no_coroutine_traits_bad_arg_yield() {
|
||||
co_yield a; // expected-error {{include <coroutine>}}
|
||||
// expected-error@-1 {{use of undeclared identifier 'a'}}
|
||||
co_yield a; // expected-error {{use of undeclared identifier 'a'}}
|
||||
}
|
||||
|
||||
|
||||
void no_coroutine_traits_bad_arg_return() {
|
||||
co_return a; // expected-error {{include <coroutine>}}
|
||||
// expected-error@-1 {{use of undeclared identifier 'a'}}
|
||||
co_return a; // expected-error {{use of undeclared identifier 'a'}}
|
||||
}
|
||||
|
||||
void no_coroutine_traits() {
|
||||
@ -208,8 +205,7 @@ void mixed_yield() {
|
||||
|
||||
void mixed_yield_invalid() {
|
||||
co_yield blah; // expected-error {{use of undeclared identifier}}
|
||||
// expected-note@-1 {{function is a coroutine due to use of 'co_yield'}}
|
||||
return; // expected-error {{return statement not allowed in coroutine}}
|
||||
return;
|
||||
}
|
||||
|
||||
void mixed_yield_return_first(bool b) {
|
||||
@ -231,8 +227,7 @@ void mixed_return_for_range(bool b, T t) {
|
||||
template <class T>
|
||||
void mixed_yield_template(T) {
|
||||
co_yield blah; // expected-error {{use of undeclared identifier}}
|
||||
// expected-note@-1 {{function is a coroutine due to use of 'co_yield'}}
|
||||
return; // expected-error {{return statement not allowed in coroutine}}
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -314,10 +309,9 @@ template void mixed_coreturn_template(void_tag, bool, int); // expected-note {{r
|
||||
template <class T>
|
||||
void mixed_coreturn_template2(bool b, T) {
|
||||
if (b)
|
||||
co_return v; // expected-note {{use of 'co_return'}}
|
||||
// expected-error@-1 {{use of undeclared identifier 'v'}}
|
||||
co_return v; // expected-error {{use of undeclared identifier 'v'}}
|
||||
else
|
||||
return; // expected-error {{not allowed in coroutine}}
|
||||
return;
|
||||
}
|
||||
|
||||
struct promise_handle;
|
||||
|
||||
67
clang/test/SemaCXX/cxx-delayed-typo-correction-crashes.cpp
Normal file
67
clang/test/SemaCXX/cxx-delayed-typo-correction-crashes.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
namespace GH138850 {
|
||||
void test() {
|
||||
int tmp = add(int, 0, 0); // expected-error {{expected '(' for function-style cast or type construction}} \
|
||||
expected-note {{previous definition is here}}
|
||||
uint tmp = add(uint, 1, 1); // expected-error {{use of undeclared identifier 'uint'; did you mean 'int'?}} \
|
||||
expected-error {{redefinition of 'tmp'}} \
|
||||
expected-error {{use of undeclared identifier 'uint'}}
|
||||
call(void, f, (int)tmp); // expected-error {{expected '(' for function-style cast or type construction}} \
|
||||
expected-error {{use of undeclared identifier 'f'}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace GH107840 {
|
||||
struct tm {}; // expected-note {{'tm' declared here}}
|
||||
|
||||
auto getCache = [&] { // expected-error {{non-local lambda expression cannot have a capture-default}}
|
||||
::foo([=] { // expected-error {{no member named 'foo' in the global namespace}}
|
||||
tms time; // expected-error {{unknown type name 'tms'; did you mean 'tm'?}}
|
||||
(void)time;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
namespace GH59391 {
|
||||
template <typename b> class c {
|
||||
c(b);
|
||||
b e;
|
||||
void f() {
|
||||
for (auto core : a::c(cores)) { // expected-error {{use of undeclared identifier 'cores'}} \
|
||||
expected-error {{use of undeclared identifier 'a'}}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace GH45915 {
|
||||
short g_volatile_ushort; // expected-note {{'g_volatile_ushort' declared here}}
|
||||
namespace a {
|
||||
int b = l_volatile_uwchar.a ::c ::~d<>; // expected-error {{use of undeclared identifier 'l_volatile_uwchar'}} \
|
||||
expected-error {{no member named 'd' in namespace 'GH45915::a'}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace GH45891 {
|
||||
int a = b.c < enum , > :: template ~d < > [ e; // expected-error {{use of undeclared identifier 'b'}} \
|
||||
expected-error {{expected identifier or '{'}} \
|
||||
expected-error {{expected ';' after top level declarator}}
|
||||
}
|
||||
|
||||
namespace GH32903 {
|
||||
void
|
||||
B(
|
||||
char cat_dog_3, char cat_dog_2, char cat_dog_1, char cat_dog_0, char pigeon_dog_3, char pigeon_dog_2,
|
||||
char pigeon_dog_1, char pigeon_dog_0, short &elefant15_lion, short &elefant14_lion, short &elefant13_lion, // expected-note 3 {{declared here}}
|
||||
short &elefant12_lion, short &elefant11_lion, short &elefant10_lion, short &elefant9_lion, short &elefant8_lion, // expected-note 5 {{declared here}}
|
||||
short &elefant7_lion, short &elefant6_lion, short &elefant5_lion, short &elefant4_lion, short &elefant3_lion, // expected-note 2 {{declared here}}
|
||||
short &elefant2_lion, short &elefant1_lion, short &elefant0_lion, char& no_animal)
|
||||
{
|
||||
|
||||
A( // FIXME: it's surprising that we don't issue a "use of undeclared identifier" diagnostic for the call itself.
|
||||
elefant_15_lion, elefant_14_lion, elefant_13_lion, elefant_12_lion, elefant_11_lion, elefant_10_lion, elefant_9_lion, // expected-error 7 {{use of undeclared identifier}}
|
||||
elefant_8_lion, elefant_7_lion, elefant_6_lion, elefant_5_lion, elefant_4_lion, elefant_3_lion, elefant_2_lion, // expected-error 7 {{use of undeclared identifier}}
|
||||
elefant_1_lion, elefant_0_lion, no_animal, other_mammal); // expected-error 3 {{use of undeclared identifier}}
|
||||
}
|
||||
}
|
||||
@ -121,7 +121,8 @@ void for_range() {
|
||||
}
|
||||
|
||||
int error_recovery() {
|
||||
auto [foobar]; // expected-error {{requires an initializer}}
|
||||
auto [foobar]; // expected-error {{requires an initializer}} \
|
||||
expected-note {{'foobar' declared here}}
|
||||
return foobar_; // expected-error {{undeclared identifier 'foobar_'}}
|
||||
}
|
||||
|
||||
|
||||
19
clang/test/SemaCXX/cxx20-delayed-typo-correction-crashes.cpp
Normal file
19
clang/test/SemaCXX/cxx20-delayed-typo-correction-crashes.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
|
||||
|
||||
#include "Inputs/std-coroutine.h"
|
||||
|
||||
namespace GH58172 {
|
||||
template<typename Fn>
|
||||
int f2(int, Fn&&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f1()
|
||||
{
|
||||
return f2(v1, []() -> task<int> { // expected-error {{no template named 'task'}} \
|
||||
expected-error {{use of undeclared identifier 'v1'}}
|
||||
co_return v2; // expected-error {{use of undeclared identifier 'v2'}}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -61,7 +61,7 @@ struct A : X<int> { // expected-error {{no template named 'X'}}
|
||||
// Similarly for treating overload sets of functions as template names.
|
||||
struct g<int> {}; // expected-error {{'g' refers to a function template}}
|
||||
g<int>::Y xy; // expected-error {{no template named 'g'}} FIXME lies
|
||||
void xf(g<int> x); // expected-error {{variable has incomplete type 'void'}} expected-error 1+{{}} expected-note {{}}
|
||||
void xf(g<int> x); // expected-error {{variable has incomplete type 'void'}} expected-error 1+{{}}
|
||||
struct B : g<int> { // expected-error {{expected class name}}
|
||||
B() : g<int>() {} // expected-error {{expected class member or base class name}}
|
||||
};
|
||||
|
||||
@ -553,14 +553,11 @@ namespace crash_on_invalid_base_dtor {
|
||||
struct Test {
|
||||
virtual ~Test();
|
||||
};
|
||||
struct Baz : public Test { // expected-warning {{non-virtual destructor}}
|
||||
struct Baz : public Test {
|
||||
Baz() {}
|
||||
~Baz() = defaul; // expected-error {{undeclared identifier 'defaul'}} \
|
||||
// expected-error {{initializer on function}} \
|
||||
// expected-note {{overridden virtual function is here}}
|
||||
~Baz() = defaul; // expected-error {{undeclared identifier 'defaul'}}
|
||||
};
|
||||
struct Foo : public Baz { // expected-error {{cannot override a non-deleted function}} \
|
||||
// expected-note {{destructor of 'Foo' is implicitly deleted}}
|
||||
struct Foo : public Baz {
|
||||
Foo() {}
|
||||
};
|
||||
}
|
||||
@ -579,11 +576,9 @@ static_assert(!__is_trivially_constructible(Foo, Foo &&), "");
|
||||
|
||||
namespace GH97230 {
|
||||
struct X {
|
||||
~X() = defaul; // expected-error {{initializer on function does not look like a pure-specifier}} \
|
||||
// expected-error {{use of undeclared identifier 'defaul'}}
|
||||
~X() = defaul; // expected-error {{use of undeclared identifier 'defaul'}}
|
||||
};
|
||||
struct Y : X {} y1{ }; // expected-error {{call to implicitly-deleted default constructor of 'struct Y'}} \
|
||||
// expected-note {{default constructor of 'Y' is implicitly deleted because base class 'X' has no destructor}}
|
||||
struct Y : X {} y1{ };
|
||||
}
|
||||
|
||||
namespace GH121706 {
|
||||
|
||||
@ -2,12 +2,16 @@
|
||||
|
||||
namespace GH61885 {
|
||||
void similar() { // expected-note {{'similar' declared here}}
|
||||
if constexpr (similer<>) {} // expected-error {{use of undeclared identifier 'similer'; did you mean 'similar'?}}
|
||||
if constexpr (similer<>) {} // expected-error {{use of undeclared identifier 'similer'; did you mean 'similar'?}} \
|
||||
expected-warning {{address of function 'similar<>' will always evaluate to 'true'}} \
|
||||
expected-note {{prefix with the address-of operator to silence this warning}}
|
||||
}
|
||||
void a() { if constexpr (__adl_swap<>) {}} // expected-error{{use of undeclared identifier '__adl_swap'; did you mean '__sync_swap'?}}
|
||||
void a() { if constexpr (__adl_swap<>) {}} // expected-error{{use of undeclared identifier '__adl_swap'}}
|
||||
|
||||
int AA() { return true;} // expected-note {{'AA' declared here}}
|
||||
|
||||
void b() { if constexpr (AAA<>) {}} // expected-error {{use of undeclared identifier 'AAA'; did you mean 'AA'?}}
|
||||
void b() { if constexpr (AAA<>) {}} // expected-error {{use of undeclared identifier 'AAA'; did you mean 'AA'?}} \
|
||||
expected-warning {{address of function 'AA<>' will always evaluate to 'true'}} \
|
||||
expected-note {{prefix with the address-of operator to silence this warning}}
|
||||
}
|
||||
|
||||
|
||||
@ -96,11 +96,11 @@ namespace test5 {
|
||||
namespace PR7508 {
|
||||
struct A {
|
||||
struct CleanupScope {};
|
||||
void PopCleanupBlock(); // expected-note{{'PopCleanupBlock' declared here}}
|
||||
void PopCleanupBlock();
|
||||
};
|
||||
|
||||
void foo(A &a) {
|
||||
a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'; did you mean 'PopCleanupBlock'?}}
|
||||
a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'}}
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ namespace PR15045 {
|
||||
}
|
||||
|
||||
struct bar {
|
||||
void func(); // expected-note {{'func' declared here}}
|
||||
void func();
|
||||
};
|
||||
|
||||
struct foo {
|
||||
@ -207,7 +207,7 @@ namespace PR15045 {
|
||||
|
||||
// Show that recovery has happened by also triggering typo correction
|
||||
e->Func(); // expected-error {{member reference type 'bar' is not a pointer; did you mean to use '.'?}} \
|
||||
// expected-error {{no member named 'Func' in 'PR15045::bar'; did you mean 'func'?}}
|
||||
// expected-error {{no member named 'Func' in 'PR15045::bar'}}
|
||||
|
||||
// Make sure a fixit isn't given in the case that the '->' isn't actually
|
||||
// the problem (the problem is with the return value of an operator->).
|
||||
|
||||
@ -409,7 +409,8 @@ T1<C2::N1> var_1a;
|
||||
T1<C2:N1> var_1b; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
|
||||
template<int N> int F() {}
|
||||
int (*X1)() = (B1::B2 ? F<1> : F<2>);
|
||||
int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
|
||||
int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} \
|
||||
expected-note{{'PR18587::X2' declared here}}
|
||||
|
||||
// Bit fields + templates
|
||||
struct S7a {
|
||||
@ -445,7 +446,8 @@ namespace PR16951 {
|
||||
|
||||
int x4 = enumerator_2::ENUMERATOR_2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}}
|
||||
int x5 = enumerator_2::X2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \
|
||||
// expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}}
|
||||
// expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}} \
|
||||
// expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'int (*)()'}}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
// Don't crash (PR13394).
|
||||
|
||||
namespace stretch_v1 {
|
||||
struct closure_t {
|
||||
const stretch_v1::ops_t* d_methods; // expected-error {{no type named 'ops_t' in namespace 'stretch_v1'}}
|
||||
};
|
||||
}
|
||||
namespace gatekeeper_v1 {
|
||||
namespace gatekeeper_factory_v1 {
|
||||
struct closure_t { // expected-note {{'closure_t' declared here}} expected-note {{'gatekeeper_factory_v1::closure_t' declared here}}
|
||||
gatekeeper_v1::closure_t* create(); // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean simply 'closure_t'?}}
|
||||
};
|
||||
}
|
||||
// FIXME: Typo correction should remove the 'gatekeeper_v1::' name specifier
|
||||
gatekeeper_v1::closure_t *x; // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean 'gatekeeper_factory_v1::closure_t'}}
|
||||
}
|
||||
|
||||
namespace Foo {
|
||||
struct Base {
|
||||
void Bar() {} // expected-note{{'Bar' declared here}}
|
||||
};
|
||||
}
|
||||
|
||||
struct Derived : public Foo::Base {
|
||||
void test() {
|
||||
Foo::Bar(); // expected-error{{no member named 'Bar' in namespace 'Foo'; did you mean simply 'Bar'?}}
|
||||
}
|
||||
};
|
||||
@ -130,5 +130,5 @@ void cxx_unresolved_expr() {
|
||||
// CXXUnresolvedConstructExpr, and the missing ')' gives it an invalid source
|
||||
// location for its rparen. Check that emitting a diag on the range of the
|
||||
// expr doesn't assert.
|
||||
return int(undeclared, 4; // expected-error {{expected ')'}} expected-note{{to match this '('}} expected-error {{use of undeclared identifier 'undeclared'}}
|
||||
return int(undeclared, 4; // expected-error {{use of undeclared identifier 'undeclared'}}
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@ auto check1() {
|
||||
return s; // expected-error {{use of undeclared identifier 's'}}
|
||||
}
|
||||
|
||||
int test = 11; // expected-note 2 {{'test' declared here}}
|
||||
int test = 11; // expected-note 3 {{'test' declared here}}
|
||||
auto check2() {
|
||||
return "s";
|
||||
return tes; // expected-error {{use of undeclared identifier 'tes'; did you mean 'test'?}}
|
||||
return tes; // expected-error {{use of undeclared identifier 'tes'}}
|
||||
// expected-error@-1 {{deduced as 'int' here but deduced as 'const char *' in earlier}}
|
||||
}
|
||||
|
||||
@ -16,9 +16,8 @@ template <class A> struct is_same<A,A> { static constexpr bool value = true; };
|
||||
|
||||
auto L1 = [] { return s; }; // expected-error {{use of undeclared identifier 's'}}
|
||||
using T1 = decltype(L1());
|
||||
// FIXME: Suppress the 'undeclared identifier T1' diagnostic, the UsingDecl T1 is discarded because of an invalid L1().
|
||||
static_assert(is_same<T1, void>::value, "Return statement should be discarded"); // expected-error {{use of undeclared identifier 'T1'}}
|
||||
auto L2 = [] { return tes; }; // expected-error {{use of undeclared identifier 'tes'; did you mean 'test'?}}
|
||||
static_assert(is_same<T1, void>::value, "Return statement should be discarded");
|
||||
auto L2 = [] { return tes; }; // expected-error {{use of undeclared identifier 'tes'}}
|
||||
using T2 = decltype(L2());
|
||||
static_assert(is_same<T2, int>::value, "Return statement was corrected");
|
||||
|
||||
@ -32,13 +31,13 @@ FooRecord::NestedNamespace::type x; // expected-error {{no member named 'NestedN
|
||||
|
||||
void cast_expr(int g) { +int(n)(g); } // expected-error {{undeclared identifier 'n'}}
|
||||
|
||||
void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}}
|
||||
void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}} \
|
||||
expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
|
||||
|
||||
namespace NoCrash {
|
||||
class S {
|
||||
void Function(int a) {
|
||||
unknown1(unknown2, Function, unknown3); // expected-error 2{{use of undeclared identifier}} \
|
||||
expected-error {{reference to non-static member function must be called}}
|
||||
unknown1(unknown2, Function, unknown3); // expected-error 2{{use of undeclared identifier}}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -46,8 +45,6 @@ class S {
|
||||
namespace NoCrashOnCheckArgAlignment {
|
||||
template <typename a> void b(a &);
|
||||
void test() {
|
||||
for (auto file_data :b(files_db_data)); // expected-error {{use of undeclared identifier 'files_db_data'; did you mean 'file_data'?}} \
|
||||
// expected-note {{'file_data' declared here}} \
|
||||
// expected-error {{cannot use type 'void' as a range}}
|
||||
for (auto file_data :b(files_db_data)); // expected-error {{use of undeclared identifier 'files_db_data'}}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user