diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-11-06 19:31:51 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-11-06 19:31:51 +0000 |
commit | 79c927bfe9fc9d2a3972e9f906bce30b96e2e852 (patch) | |
tree | 2a01e156111a7609836018c851b05bfd83b96386 /clang/lib | |
parent | 41b99dce592ab3150a11ed84e0328bf3b3b78ae7 (diff) | |
download | bcm5719-llvm-79c927bfe9fc9d2a3972e9f906bce30b96e2e852.tar.gz bcm5719-llvm-79c927bfe9fc9d2a3972e9f906bce30b96e2e852.zip |
Add a limit to the length of a sequence of 'operator->' functions we will
follow when building a class member access expression. Based on a patch by
Rahul Jain!
llvm-svn: 194161
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 47 |
3 files changed, 48 insertions, 6 deletions
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 5ac2268ee3e..7c987191d80 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -2832,6 +2832,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { + CmdArgs.push_back("-foperator-arrow-depth"); + CmdArgs.push_back(A->getValue()); + } + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { CmdArgs.push_back("-fconstexpr-depth"); CmdArgs.push_back(A->getValue()); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index d419d8a9eaf..c1999e84c44 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1322,6 +1322,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.MathErrno = !Opts.OpenCL && Args.hasArg(OPT_fmath_errno); Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 256, Diags); + Opts.ArrowDepth = + getLastArgIntValue(Args, OPT_foperator_arrow_depth, 256, Diags); Opts.ConstexprCallDepth = getLastArgIntValue(Args, OPT_fconstexpr_depth, 512, Diags); Opts.ConstexprStepLimit = diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 6f72d6598eb..2e71270b4e8 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5149,6 +5149,32 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { return Owned(E); } +/// Note a set of 'operator->' functions that were used for a member access. +static void noteOperatorArrows(Sema &S, + llvm::ArrayRef<FunctionDecl *> OperatorArrows) { + unsigned SkipStart = OperatorArrows.size(), SkipCount = 0; + // FIXME: Make this configurable? + unsigned Limit = 9; + if (OperatorArrows.size() > Limit) { + // Produce Limit-1 normal notes and one 'skipping' note. + SkipStart = (Limit - 1) / 2 + (Limit - 1) % 2; + SkipCount = OperatorArrows.size() - (Limit - 1); + } + + for (unsigned I = 0; I < OperatorArrows.size(); /**/) { + if (I == SkipStart) { + S.Diag(OperatorArrows[I]->getLocation(), + diag::note_operator_arrows_suppressed) + << SkipCount; + I += SkipCount; + } else { + S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrow_here) + << OperatorArrows[I]->getCallResultType(); + ++I; + } + } +} + ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, @@ -5181,15 +5207,25 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, // [...] When operator->returns, the operator-> is applied to the value // returned, with the original second operand. if (OpKind == tok::arrow) { + QualType StartingType = BaseType; bool NoArrowOperatorFound = false; bool FirstIteration = true; FunctionDecl *CurFD = dyn_cast<FunctionDecl>(CurContext); // The set of types we've considered so far. llvm::SmallPtrSet<CanQualType,8> CTypes; - SmallVector<SourceLocation, 8> Locations; + SmallVector<FunctionDecl*, 8> OperatorArrows; CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { + if (OperatorArrows.size() >= getLangOpts().ArrowDepth) { + Diag(OpLoc, diag::err_operator_arrow_depth_exceeded) + << BaseType << getLangOpts().ArrowDepth << Base->getSourceRange(); + noteOperatorArrows(*this, OperatorArrows); + Diag(OpLoc, diag::note_operator_arrow_depth) + << getLangOpts().ArrowDepth; + return ExprError(); + } + Result = BuildOverloadedArrowExpr( S, Base, OpLoc, // When in a template specialization and on the first loop iteration, @@ -5203,7 +5239,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, if (NoArrowOperatorFound) { if (FirstIteration) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << 1 << Base->getSourceRange() + << StartingType << 1 << Base->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "."); OpKind = tok::period; break; @@ -5220,13 +5256,12 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, } Base = Result.get(); if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(Base)) - Locations.push_back(OpCall->getDirectCallee()->getLocation()); + OperatorArrows.push_back(OpCall->getDirectCallee()); BaseType = Base->getType(); CanQualType CBaseType = Context.getCanonicalType(BaseType); if (!CTypes.insert(CBaseType)) { - Diag(OpLoc, diag::err_operator_arrow_circular); - for (unsigned i = 0; i < Locations.size(); i++) - Diag(Locations[i], diag::note_declared_at); + Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType; + noteOperatorArrows(*this, OperatorArrows); return ExprError(); } FirstIteration = false; |