summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/plugin.cxx
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2017-11-15 17:41:22 +0100
committerStephan Bergmann <sbergman@redhat.com>2017-11-16 16:33:24 +0100
commit4ff66e42bfd7d03020d9fd09bc24aef92d92ecd0 (patch)
tree53ed50d31961c66b9743bb28f0064c15d85a6247 /compilerplugins/clang/plugin.cxx
parentfa7f2ec536b477acb6ba2cc1ec42b7f6ec97a024 (diff)
Make checkIdenticalDefaultArguments more precise
...by structurally comparing complex constexpr exprs that use template functions that happen to not have been instantiated, so Expr::EvaluateAsRValue et al would fail. (Which happened with SFX_PRINTER_ALL in SfxViewShell::SetPrinter, include/sfx2/viewsh.hxx.) Now all of the LO code base should compile without causing checkIdenticalDefaultArguments to return Maybe. Change-Id: I2b103418c2c68f6d2242535c9cca3222a2508778 Reviewed-on: https://gerrit.libreoffice.org/44773 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins/clang/plugin.cxx')
-rw-r--r--compilerplugins/clang/plugin.cxx76
1 files changed, 76 insertions, 0 deletions
diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx
index ed179d9b2b65..3c716112cd47 100644
--- a/compilerplugins/clang/plugin.cxx
+++ b/compilerplugins/clang/plugin.cxx
@@ -38,6 +38,76 @@ Expr const * skipImplicit(Expr const * expr) {
return expr;
}
+bool structurallyIdentical(Stmt const * stmt1, Stmt const * stmt2) {
+ if (stmt1->getStmtClass() != stmt2->getStmtClass()) {
+ return false;
+ }
+ switch (stmt1->getStmtClass()) {
+ case Stmt::CXXConstructExprClass:
+ if (cast<CXXConstructExpr>(stmt1)->getConstructor()->getCanonicalDecl()
+ != cast<CXXConstructExpr>(stmt2)->getConstructor()->getCanonicalDecl())
+ {
+ return false;
+ }
+ break;
+ case Stmt::DeclRefExprClass:
+ if (cast<DeclRefExpr>(stmt1)->getDecl()->getCanonicalDecl()
+ != cast<DeclRefExpr>(stmt2)->getDecl()->getCanonicalDecl())
+ {
+ return false;
+ }
+ break;
+ case Stmt::ImplicitCastExprClass:
+ {
+ auto const e1 = cast<ImplicitCastExpr>(stmt1);
+ auto const e2 = cast<ImplicitCastExpr>(stmt2);
+ if (e1->getCastKind() != e2->getCastKind()
+ || e1->getType().getCanonicalType() != e2->getType().getCanonicalType())
+ {
+ return false;
+ }
+ break;
+ }
+ case Stmt::MemberExprClass:
+ {
+ auto const e1 = cast<MemberExpr>(stmt1);
+ auto const e2 = cast<MemberExpr>(stmt2);
+ if (e1->isArrow() != e2->isArrow()
+ || e1->getType().getCanonicalType() != e2->getType().getCanonicalType())
+ {
+ return false;
+ }
+ break;
+ }
+ case Stmt::CXXMemberCallExprClass:
+ case Stmt::CXXOperatorCallExprClass:
+ if (cast<Expr>(stmt1)->getType().getCanonicalType()
+ != cast<Expr>(stmt2)->getType().getCanonicalType())
+ {
+ return false;
+ }
+ break;
+ case Stmt::MaterializeTemporaryExprClass:
+ case Stmt::ParenExprClass:
+ break;
+ default:
+ // Conservatively assume non-identical for expressions that don't happen for us in practice
+ // when compiling the LO code base (and for which the above set of supported classes would
+ // need to be extended):
+ return false;
+ }
+ auto i1 = stmt1->child_begin();
+ auto e1 = stmt1->child_end();
+ auto i2 = stmt2->child_begin();
+ auto e2 = stmt2->child_end();
+ for (; i1 != e1; ++i1, ++i2) {
+ if (i2 == e2 || !structurallyIdentical(*i1, *i2)) {
+ return false;
+ }
+ }
+ return i2 == e2;
+}
+
}
Plugin::Plugin( const InstantiationData& data )
@@ -294,6 +364,12 @@ Plugin::IdenticalDefaultArgumentsResult Plugin::checkIdenticalDefaultArguments(
}
break;
}
+ // If the EvaluateAsRValue derivatives above failed because the arguments use e.g. (constexpr)
+ // function template specializations that happen to not have been instantiated in this TU, try a
+ // structural comparison of the arguments:
+ if (structurallyIdentical(argument1, argument2)) {
+ return IdenticalDefaultArgumentsResult::Yes;
+ }
return IdenticalDefaultArgumentsResult::Maybe;
}