summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-11-06 19:31:51 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-11-06 19:31:51 +0000
commit79c927bfe9fc9d2a3972e9f906bce30b96e2e852 (patch)
tree2a01e156111a7609836018c851b05bfd83b96386
parent41b99dce592ab3150a11ed84e0328bf3b3b78ae7 (diff)
downloadbcm5719-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
-rw-r--r--clang/docs/UsersManual.rst7
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td10
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/Driver/CC1Options.td2
-rw-r--r--clang/include/clang/Driver/Options.td2
-rw-r--r--clang/lib/Driver/Tools.cpp5
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp2
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp47
-rw-r--r--clang/test/SemaCXX/operator-arrow-depth.cpp26
9 files changed, 96 insertions, 7 deletions
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 4dc8bbfec10..e0a68384ad3 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1299,7 +1299,12 @@ Controlling implementation limits
.. option:: -ftemplate-depth=N
Sets the limit for recursively nested template instantiations to N. The
- default is 1024.
+ default is 256.
+
+.. option:: -foperator-arrow-depth=N
+
+ Sets the limit for iterative calls to 'operator->' functions to N. The
+ default is 256.
.. _objc:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6289d5a56b9..54b74debe70 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5144,6 +5144,16 @@ def err_capture_block_variable : Error<
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
+def err_operator_arrow_depth_exceeded : Error<
+ "use of 'operator->' on type %0 would invoke a sequence of more than %1 "
+ "'operator->' calls">;
+def note_operator_arrow_here : Note<
+ "'operator->' declared here produces an object of type %0">;
+def note_operator_arrows_suppressed : Note<
+ "(skipping %0 'operator->'%s0 in backtrace)">;
+def note_operator_arrow_depth : Note<
+ "use -foperator-arrow-depth=N to increase 'operator->' limit">;
+
def err_pseudo_dtor_base_not_scalar : Error<
"object expression of non-scalar type %0 cannot be used in a "
"pseudo-destructor expression">;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 72b563dfe34..5a1025cba7e 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -161,6 +161,8 @@ ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,
ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
"signed integer overflow handling")
+BENIGN_LANGOPT(ArrowDepth, 32, 256,
+ "maximum number of operator->s to follow")
BENIGN_LANGOPT(InstantiationDepth, 32, 256,
"maximum template instantiation depth")
BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td
index 6b7dac8e444..85cfdcf3946 100644
--- a/clang/include/clang/Driver/CC1Options.td
+++ b/clang/include/clang/Driver/CC1Options.td
@@ -442,6 +442,8 @@ def ftype_visibility : Separate<["-"], "ftype-visibility">,
HelpText<"Default type visibility">;
def ftemplate_depth : Separate<["-"], "ftemplate-depth">,
HelpText<"Maximum depth of recursive template instantiation">;
+def foperator_arrow_depth : Separate<["-"], "foperator-arrow-depth">,
+ HelpText<"Maximum number of 'operator->'s to call for a member access">;
def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">,
HelpText<"Maximum depth of recursive constexpr function calls">;
def fconstexpr_steps : Separate<["-"], "fconstexpr-steps">,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index cc2de9f914f..faaaee1e931 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -776,6 +776,8 @@ def ftemplate_depth_EQ : Joined<["-"], "ftemplate-depth=">, Group<f_Group>;
def ftemplate_depth_ : Joined<["-"], "ftemplate-depth-">, Group<f_Group>;
def ftemplate_backtrace_limit_EQ : Joined<["-"], "ftemplate-backtrace-limit=">,
Group<f_Group>;
+def foperator_arrow_depth_EQ : Joined<["-"], "foperator-arrow-depth=">,
+ Group<f_Group>;
def ftest_coverage : Flag<["-"], "ftest-coverage">, Group<f_Group>;
def fvectorize : Flag<["-"], "fvectorize">, Group<f_Group>,
HelpText<"Enable the loop vectorization passes">;
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;
diff --git a/clang/test/SemaCXX/operator-arrow-depth.cpp b/clang/test/SemaCXX/operator-arrow-depth.cpp
new file mode 100644
index 00000000000..4e098823ae8
--- /dev/null
+++ b/clang/test/SemaCXX/operator-arrow-depth.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DMAX=128 -foperator-arrow-depth 128
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DMAX=2 -foperator-arrow-depth 2
+// RUN: %clang -fsyntax-only -Xclang -verify %s -DMAX=10 -foperator-arrow-depth=10
+
+template<int N> struct B;
+template<int N> struct A {
+ B<N> operator->(); // expected-note +{{'operator->' declared here produces an object of type 'B<}}
+};
+template<int N> struct B {
+ A<N-1> operator->(); // expected-note +{{'operator->' declared here produces an object of type 'A<}}
+#if MAX != 2
+ // expected-note-re@-2 {{(skipping (120|2) 'operator->'s in backtrace)}}
+#endif
+};
+
+struct X { int n; };
+template<> struct B<1> {
+ X *operator->();
+};
+
+A<MAX/2> good;
+int n = good->n;
+
+B<MAX/2 + 1> bad;
+int m = bad->n; // expected-error-re {{use of 'operator->' on type 'B<(1|5|64)>' would invoke a sequence of more than (2|10|128) 'operator->' calls}}
+ // expected-note@-1 {{use -foperator-arrow-depth=N to increase 'operator->' limit}}
OpenPOWER on IntegriCloud