summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Trieu <rtrieu@google.com>2019-05-04 04:22:33 +0000
committerRichard Trieu <rtrieu@google.com>2019-05-04 04:22:33 +0000
commitcf9bd8ade7537bc85fa180dcd4e82ef7cb07bcbb (patch)
tree9576b832487d71694453295b28437e9e6f7bd1b7
parent28a1936f6dff5f638d61a922aa6edc90be4c8d8e (diff)
downloadbcm5719-llvm-cf9bd8ade7537bc85fa180dcd4e82ef7cb07bcbb.tar.gz
bcm5719-llvm-cf9bd8ade7537bc85fa180dcd4e82ef7cb07bcbb.zip
Reduce amount of work ODR hashing does.
When a FunctionProtoType is in the original type in a DecayedType, the decayed type is a PointerType which points back the original FunctionProtoType. The visitor for ODRHashing will attempt to process both Type's, doing double work. By chaining together multiple DecayedType's and FunctionProtoType's, this would result in 2^N Type's visited only N DecayedType's and N FunctionProtoType's exsit. Another bug where VisitDecayedType and VisitAdjustedType did redundant work doubled the work at each level, giving 4^N Type's visited. This patch removed the double work and detects when a FunctionProtoType decays to itself to only check the Type once. This lowers the exponential runtime to linear runtime. Fixes https://bugs.llvm.org/show_bug.cgi?id=41625 llvm-svn: 359960
-rw-r--r--clang/lib/AST/ODRHash.cpp30
-rw-r--r--clang/test/Modules/odr_hash.cpp37
2 files changed, 63 insertions, 4 deletions
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 4f4ea67d32f..9d484bd5de5 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -703,14 +703,36 @@ public:
void VisitType(const Type *T) {}
void VisitAdjustedType(const AdjustedType *T) {
- AddQualType(T->getOriginalType());
- AddQualType(T->getAdjustedType());
+ QualType Original = T->getOriginalType();
+ QualType Adjusted = T->getAdjustedType();
+
+ // The original type and pointee type can be the same, as in the case of
+ // function pointers decaying to themselves. Set a bool and only process
+ // the type once, to prevent doubling the work.
+ SplitQualType split = Adjusted.split();
+ if (auto Pointer = dyn_cast<PointerType>(split.Ty)) {
+ if (Pointer->getPointeeType() == Original) {
+ Hash.AddBoolean(true);
+ ID.AddInteger(split.Quals.getAsOpaqueValue());
+ AddQualType(Original);
+ VisitType(T);
+ return;
+ }
+ }
+
+ // The original type and pointee type are different, such as in the case
+ // of a array decaying to an element pointer. Set a bool to false and
+ // process both types.
+ Hash.AddBoolean(false);
+ AddQualType(Original);
+ AddQualType(Adjusted);
+
VisitType(T);
}
void VisitDecayedType(const DecayedType *T) {
- AddQualType(T->getDecayedType());
- AddQualType(T->getPointeeType());
+ // getDecayedType and getPointeeType are derived from getAdjustedType
+ // and don't need to be separately processed.
VisitAdjustedType(T);
}
diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp
index e4c5ba6f82a..f22a8b8f8a0 100644
--- a/clang/test/Modules/odr_hash.cpp
+++ b/clang/test/Modules/odr_hash.cpp
@@ -4587,6 +4587,43 @@ int num = bar();
#endif
}
+namespace FunctionProtoTypeDecay {
+#if defined(FIRST)
+struct S1 {
+ struct X {};
+ using Y = X(X());
+};
+#elif defined(SECOND)
+struct S1 {
+ struct X {};
+ using Y = X(X(X()));
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'FunctionProtoTypeDecay::S1::Y' from module 'FirstModule' is not present in definition of 'FunctionProtoTypeDecay::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'Y' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ struct X {};
+ using Y =
+ X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(
+ X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(
+ X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(
+ X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(X(
+ ))))))))))))))))
+ ))))))))))))))))
+ ))))))))))))))))
+ ))))))))))))))));
+};
+#elif defined(SECOND)
+#else
+S2 s2;
+#endif
+
+}
+
// Keep macros contained to one file.
#ifdef FIRST
#undef FIRST
OpenPOWER on IntegriCloud