Skip to content

Commit 0c2b38c

Browse files
Fix TagDecl de-nesting when the outer TagDecl is preceded by qualifiers.
TODO: Add regression tests.
1 parent 220234c commit 0c2b38c

File tree

3 files changed

+56
-16
lines changed

3 files changed

+56
-16
lines changed

clang/include/clang/3C/MultiDecls.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,21 @@ struct MultiDeclInfo {
158158
bool AlreadyRewritten = false;
159159
};
160160

161-
// All multi-decls, keyed by the common beginning source location of their
162-
// members. Note that the beginning source location of TagDefToSplit may be
163-
// later if there is a keyword such as `static` or `typedef` in between.
164-
typedef std::map<SourceLocation, MultiDeclInfo> TUMultiDeclsInfo;
161+
struct TUMultiDeclsInfo {
162+
// All multi-decls, keyed by the common beginning source location of their
163+
// members. Note that the beginning source location of TagDefToSplit may be
164+
// later if there is a keyword such as `static` or `typedef` in between.
165+
std::map<SourceLocation, MultiDeclInfo> MultiDeclsByBeginLoc;
166+
167+
// Map from a tag definition to its containing multi-decl (if it is part of
168+
// one). Note that the TagDefToSplit of the MultiDeclInfo is not guaranteed to
169+
// equal the TagDecl: it may be null in the `typedef struct { ... } T` case.
170+
//
171+
// Note that the MultiDeclInfo pointers remain valid for as long as the
172+
// MultiDeclInfo objects remain in MultiDeclsByBeginLoc: see
173+
// https://en.cppreference.com/w/cpp/container#Iterator_invalidation.
174+
std::map<TagDecl *, MultiDeclInfo *> ContainingMultiDeclOfTagDecl;
175+
};
165176

166177
class ProgramMultiDeclsInfo {
167178
private:
@@ -200,6 +211,7 @@ class ProgramMultiDeclsInfo {
200211
llvm::Optional<std::string> getTypeStrOverride(const Type *Ty,
201212
const ASTContext &C);
202213
MultiDeclInfo *findContainingMultiDecl(MultiDeclMemberDecl *MMD);
214+
MultiDeclInfo *findContainingMultiDecl(TagDecl *TD);
203215
bool wasBaseTypeRenamed(Decl *D);
204216
};
205217

clang/lib/3C/DeclRewriter.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,16 +276,35 @@ void DeclRewriter::denestTagDecls() {
276276
// that were originally named, so we can't just use `TD->getDeclContext()`.
277277
// In any event, maybe we wouldn't want to rely on this kind of internal
278278
// Clang behavior.
279-
DeclContext *TopTagDecl = TD;
280-
for (;;) {
281-
DeclContext *Parent = TopTagDecl->getLexicalParent();
282-
if (!isa<TagDecl>(Parent))
283-
break;
284-
TopTagDecl = Parent;
285-
}
279+
TagDecl *TopTagDecl = TD;
280+
while (TagDecl *ParentTagDecl =
281+
dyn_cast<TagDecl>(TopTagDecl->getLexicalDeclContext()))
282+
TopTagDecl = ParentTagDecl;
283+
// If TopTagDecl is preceded by qualifiers, ideally we'd like to insert TD
284+
// before those qualifiers. If TopTagDecl is actually part of a multi-decl
285+
// with at least one member, then we can just use the begin location of that
286+
// multi-decl as the insertion point.
287+
//
288+
// If there are no members (so the qualifiers have no effect and generate a
289+
// compiler warning), then there isn't an easy way for us to find the source
290+
// location before the qualifiers. In that case, we just insert TD at the
291+
// begin location of TopTagDecl (after the qualifiers) and hope for the
292+
// best. In the cases we're aware of so far (storage qualifiers, including
293+
// `typedef`), this just means that the qualifiers end up applying to the
294+
// first TagDecl de-nested from TopTagDecl instead of to TopTagDecl itself,
295+
// and they generate the same compiler warning as before but on a different
296+
// TagDecl. However, we haven't confirmed that there aren't any obscure
297+
// cases that could lead to an error, such as if a qualifier is valid on one
298+
// kind of TagDecl but not another.
299+
SourceLocation InsertLoc;
300+
if (MultiDeclInfo *MDI =
301+
Info.TheMultiDeclsInfo.findContainingMultiDecl(TopTagDecl))
302+
InsertLoc = MDI->Members[0]->getBeginLoc();
303+
else
304+
InsertLoc = TopTagDecl->getBeginLoc();
286305
// TODO: Use a wrapper like rewriteSourceRange that tries harder with
287306
// macros, reports failure, etc.
288-
R.InsertText(cast<Decl>(TopTagDecl)->getBeginLoc(), DefinitionStr);
307+
R.InsertText(InsertLoc, DefinitionStr);
289308
}
290309
}
291310

clang/lib/3C/MultiDecls.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ void ProgramMultiDeclsInfo::findMultiDecls(DeclContext *DC, ASTContext &Context)
111111
if (CurrentMultiDecl == nullptr || MMD->getBeginLoc() != CurrentBeginLoc) {
112112
// We are starting a new multi-decl.
113113
CurrentBeginLoc = MMD->getBeginLoc();
114-
CurrentMultiDecl = &TUInfo[CurrentBeginLoc];
114+
CurrentMultiDecl = &TUInfo.MultiDeclsByBeginLoc[CurrentBeginLoc];
115115
assert(CurrentMultiDecl->Members.empty() &&
116116
"Multi-decl members are not consecutive in traversal order");
117117
TagDefNeedsName = false;
@@ -125,6 +125,7 @@ void ProgramMultiDeclsInfo::findMultiDecls(DeclContext *DC, ASTContext &Context)
125125
!Context.getSourceManager().isBeforeInTranslationUnit(
126126
LastTagDef->getBeginLoc(), CurrentBeginLoc)) {
127127
CurrentMultiDecl->TagDefToSplit = LastTagDef;
128+
TUInfo.ContainingMultiDeclOfTagDecl[LastTagDef] = CurrentMultiDecl;
128129

129130
// Do we need to automatically name the TagDefToSplit?
130131
if (LastTagDef->getName().empty()) {
@@ -248,11 +249,11 @@ ProgramMultiDeclsInfo::getTypeStrOverride(const Type *Ty, const ASTContext &C) {
248249

249250
MultiDeclInfo *
250251
ProgramMultiDeclsInfo::findContainingMultiDecl(MultiDeclMemberDecl *MMD) {
251-
TUMultiDeclsInfo &TUInfo = TUInfos[&MMD->getASTContext()];
252+
auto &MultiDeclsByLoc = TUInfos[&MMD->getASTContext()].MultiDeclsByBeginLoc;
252253
// Look for a MultiDeclInfo for the beginning location of MMD, then check that
253254
// the MultiDeclInfo actually contains MMD.
254-
auto It = TUInfo.find(MMD->getBeginLoc());
255-
if (It == TUInfo.end())
255+
auto It = MultiDeclsByLoc.find(MMD->getBeginLoc());
256+
if (It == MultiDeclsByLoc.end())
256257
return nullptr;
257258
MultiDeclInfo &MDI = It->second;
258259
// Hope we don't have multi-decls with so many members that this becomes a
@@ -262,6 +263,14 @@ ProgramMultiDeclsInfo::findContainingMultiDecl(MultiDeclMemberDecl *MMD) {
262263
return nullptr;
263264
}
264265

266+
MultiDeclInfo *ProgramMultiDeclsInfo::findContainingMultiDecl(TagDecl *TD) {
267+
auto &MDOfTD = TUInfos[&TD->getASTContext()].ContainingMultiDeclOfTagDecl;
268+
auto It = MDOfTD.find(TD);
269+
if (It == MDOfTD.end())
270+
return nullptr;
271+
return It->second;
272+
}
273+
265274
bool ProgramMultiDeclsInfo::wasBaseTypeRenamed(Decl *D) {
266275
// We assume that the base type was renamed if and only if D belongs to a
267276
// multi-decl marked as having the base type renamed. It might be better to

0 commit comments

Comments
 (0)