summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/ASTImporter.cpp165
-rw-r--r--clang/lib/AST/DeclBase.cpp2
2 files changed, 130 insertions, 37 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f812244ed3c..7dfcdeb8c4f 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -71,6 +71,25 @@
namespace clang {
+ template <class T>
+ SmallVector<Decl*, 2>
+ getCanonicalForwardRedeclChain(Redeclarable<T>* D) {
+ SmallVector<Decl*, 2> Redecls;
+ for (auto *R : D->getFirstDecl()->redecls()) {
+ if (R != D->getFirstDecl())
+ Redecls.push_back(R);
+ }
+ Redecls.push_back(D->getFirstDecl());
+ std::reverse(Redecls.begin(), Redecls.end());
+ return Redecls;
+ }
+
+ SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D) {
+ // Currently only FunctionDecl is supported
+ auto FD = cast<FunctionDecl>(D);
+ return getCanonicalForwardRedeclChain<FunctionDecl>(FD);
+ }
+
class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
public DeclVisitor<ASTNodeImporter, Decl *>,
public StmtVisitor<ASTNodeImporter, Stmt *> {
@@ -195,6 +214,12 @@ namespace clang {
const InContainerTy &Container,
TemplateArgumentListInfo &Result);
+ using TemplateArgsTy = SmallVector<TemplateArgument, 8>;
+ using OptionalTemplateArgsTy = Optional<TemplateArgsTy>;
+ std::tuple<FunctionTemplateDecl *, OptionalTemplateArgsTy>
+ ImportFunctionTemplateWithTemplateArgsFromSpecialization(
+ FunctionDecl *FromFD);
+
bool ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
@@ -408,6 +433,8 @@ namespace clang {
// Importing overrides.
void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
+
+ FunctionDecl *FindFunctionTemplateSpecialization(FunctionDecl *FromFD);
};
template <typename InContainerTy>
@@ -437,6 +464,25 @@ bool ASTNodeImporter::ImportTemplateArgumentListInfo<
From.arguments(), Result);
}
+std::tuple<FunctionTemplateDecl *, ASTNodeImporter::OptionalTemplateArgsTy>
+ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization(
+ FunctionDecl *FromFD) {
+ assert(FromFD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization);
+ auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
+ auto *Template = cast_or_null<FunctionTemplateDecl>(
+ Importer.Import(FTSInfo->getTemplate()));
+
+ // Import template arguments.
+ auto TemplArgs = FTSInfo->TemplateArguments->asArray();
+ TemplateArgsTy ToTemplArgs;
+ if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(),
+ ToTemplArgs)) // Error during import.
+ return std::make_tuple(Template, OptionalTemplateArgsTy());
+
+ return std::make_tuple(Template, ToTemplArgs);
+}
+
} // namespace clang
//----------------------------------------------------------------------------
@@ -2252,23 +2298,17 @@ bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD,
}
case FunctionDecl::TK_FunctionTemplateSpecialization: {
- auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
- auto *Template = cast_or_null<FunctionTemplateDecl>(
- Importer.Import(FTSInfo->getTemplate()));
- if (!Template)
- return true;
- TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
-
- // Import template arguments.
- auto TemplArgs = FTSInfo->TemplateArguments->asArray();
- SmallVector<TemplateArgument, 8> ToTemplArgs;
- if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(),
- ToTemplArgs))
+ FunctionTemplateDecl* Template;
+ OptionalTemplateArgsTy ToTemplArgs;
+ std::tie(Template, ToTemplArgs) =
+ ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD);
+ if (!Template || !ToTemplArgs)
return true;
TemplateArgumentList *ToTAList = TemplateArgumentList::CreateCopy(
- Importer.getToContext(), ToTemplArgs);
+ Importer.getToContext(), *ToTemplArgs);
+ auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
TemplateArgumentListInfo ToTAInfo;
const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten;
if (FromTAArgsAsWritten)
@@ -2277,6 +2317,7 @@ bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD,
SourceLocation POI = Importer.Import(FTSInfo->getPointOfInstantiation());
+ TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
ToFD->setFunctionTemplateSpecialization(
Template, ToTAList, /* InsertPos= */ nullptr,
TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, POI);
@@ -2312,7 +2353,31 @@ bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD,
llvm_unreachable("All cases should be covered!");
}
+FunctionDecl *
+ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) {
+ FunctionTemplateDecl* Template;
+ OptionalTemplateArgsTy ToTemplArgs;
+ std::tie(Template, ToTemplArgs) =
+ ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD);
+ if (!Template || !ToTemplArgs)
+ return nullptr;
+
+ void *InsertPos = nullptr;
+ auto *FoundSpec = Template->findSpecialization(*ToTemplArgs, InsertPos);
+ return FoundSpec;
+}
+
Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
+
+ SmallVector<Decl*, 2> Redecls = getCanonicalForwardRedeclChain(D);
+ auto RedeclIt = Redecls.begin();
+ // Import the first part of the decl chain. I.e. import all previous
+ // declarations starting from the canonical decl.
+ for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt)
+ if (!Importer.Import(*RedeclIt))
+ return nullptr;
+ assert(*RedeclIt == D);
+
// Import the major distinguishing characteristics of this function.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -2323,13 +2388,27 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (ToD)
return ToD;
- const FunctionDecl *FoundWithoutBody = nullptr;
-
+ const FunctionDecl *FoundByLookup = nullptr;
+
+ // If this is a function template specialization, then try to find the same
+ // existing specialization in the "to" context. The localUncachedLookup
+ // below will not find any specialization, but would find the primary
+ // template; thus, we have to skip normal lookup in case of specializations.
+ // FIXME handle member function templates (TK_MemberSpecialization) similarly?
+ if (D->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
+ if (FunctionDecl *FoundFunction = FindFunctionTemplateSpecialization(D)) {
+ if (D->doesThisDeclarationHaveABody() &&
+ FoundFunction->hasBody())
+ return Importer.Imported(D, FoundFunction);
+ FoundByLookup = FoundFunction;
+ }
+ }
// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
- if (!LexicalDC->isFunctionOrMethod()) {
+ else if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- unsigned IDNS = Decl::IDNS_Ordinary;
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend;
SmallVector<NamedDecl *, 2> FoundDecls;
DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (auto *FoundDecl : FoundDecls) {
@@ -2341,15 +2420,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundFunction->getType())) {
- // FIXME: Actually try to merge the body and other attributes.
- const FunctionDecl *FromBodyDecl = nullptr;
- D->hasBody(FromBodyDecl);
- if (D == FromBodyDecl && !FoundFunction->hasBody()) {
- // This function is needed to merge completely.
- FoundWithoutBody = FoundFunction;
+ if (D->doesThisDeclarationHaveABody() &&
+ FoundFunction->hasBody())
+ return Importer.Imported(D, FoundFunction);
+ FoundByLookup = FoundFunction;
break;
- }
- return Importer.Imported(D, FoundFunction);
}
// FIXME: Check for overloading more carefully, e.g., by boosting
@@ -2499,9 +2574,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
ToFunction->setParams(Parameters);
- if (FoundWithoutBody) {
+ if (FoundByLookup) {
auto *Recent = const_cast<FunctionDecl *>(
- FoundWithoutBody->getMostRecentDecl());
+ FoundByLookup->getMostRecentDecl());
ToFunction->setPreviousDecl(Recent);
}
@@ -2523,10 +2598,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction->setType(T);
}
- // Import the body, if any.
- if (Stmt *FromBody = D->getBody()) {
- if (Stmt *ToBody = Importer.Import(FromBody)) {
- ToFunction->setBody(ToBody);
+ if (D->doesThisDeclarationHaveABody()) {
+ if (Stmt *FromBody = D->getBody()) {
+ if (Stmt *ToBody = Importer.Import(FromBody)) {
+ ToFunction->setBody(ToBody);
+ }
}
}
@@ -2536,14 +2612,29 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (ImportTemplateInformation(D, ToFunction))
return nullptr;
- // Add this function to the lexical context.
- // NOTE: If the function is templated declaration, it should be not added into
- // LexicalDC. But described template is imported during import of
- // FunctionTemplateDecl (it happens later). So, we use source declaration
- // to determine if we should add the result function.
- if (!D->getDescribedFunctionTemplate())
+ bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend);
+
+ // TODO Can we generalize this approach to other AST nodes as well?
+ if (D->getDeclContext()->containsDecl(D))
+ DC->addDeclInternal(ToFunction);
+ if (DC != LexicalDC && D->getLexicalDeclContext()->containsDecl(D))
LexicalDC->addDeclInternal(ToFunction);
+ // Friend declaration's lexical context is the befriending class, but the
+ // semantic context is the enclosing scope of the befriending class.
+ // We want the friend functions to be found in the semantic context by lookup.
+ // FIXME should we handle this generically in VisitFriendDecl?
+ // In Other cases when LexicalDC != DC we don't want it to be added,
+ // e.g out-of-class definitions like void B::f() {} .
+ if (LexicalDC != DC && IsFriend) {
+ DC->makeDeclVisibleInContext(ToFunction);
+ }
+
+ // Import the rest of the chain. I.e. import all subsequent declarations.
+ for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt)
+ if (!Importer.Import(*RedeclIt))
+ return nullptr;
+
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 7b7febdc410..64fac22bace 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -1343,6 +1343,8 @@ bool DeclContext::decls_empty() const {
}
bool DeclContext::containsDecl(Decl *D) const {
+ if (hasExternalLexicalStorage())
+ LoadLexicalDeclsFromExternalStorage();
return (D->getLexicalDeclContext() == this &&
(D->NextInContextAndBits.getPointer() || D == LastDecl));
}
OpenPOWER on IntegriCloud