leonardchan added inline comments.
================ Comment at: clang/lib/Parse/ParseDecl.cpp:257-262 + bool AttrStartIsInMacro = + (StartLoc.isMacroID() && Lexer::isAtStartOfMacroExpansion( + StartLoc, SrcMgr, PP.getLangOpts())); + bool AttrEndIsInMacro = + (EndLoc.isMacroID() && + Lexer::isAtEndOfMacroExpansion(EndLoc, SrcMgr, PP.getLangOpts())); ---------------- rsmith wrote: > leonardchan wrote: > > rsmith wrote: > > > I think these checks need to be moved to the last loop of > > > `FindLocsWithCommonFileID`. Otherwise for a case like: > > > > > > ``` > > > #define THING \ > > > int *p = nullptr; > > > AS1 int *q = nullptr; > > > > > > THING > > > ``` > > > > > > ... `FindLocsWithCommonFileID` will pick out the `THING` macro and return > > > the range from the `int` token to the second semicolon, and the checks > > > here will fail. Instead, we should pick out the inner `AS1` expansion, > > > because it's the outermost macro expansion that starts with `StartLoc` > > > and ends with `EndLoc`. > > Moved, although this doesn't appear to fix this case. On closer inspection, > > when generating the vector of starting locations, the expansion location > > for `AS1` doesn't seem to be returned by `getExpansionLocStart`. It goes > > straight from the location of the `__attribute__` behind `AS1` to `THING` > > and skips `AS1`. I found this out by just dumping `StartLoc` on every > > iteration. > > > > The only way I can generate the location for `AS1` in `THING` is by also > > watching for the spelling location of each expansion, but this SourceLoc is > > not a macro ID and would not fulfill these last 2 checks. Is this intended? > > If it's a bug I don't mind addressing it if you point me in the right > > direction to start. > Right, sorry, mistake on my part. To deal with this, you need to call > `isAt{Start,End}OfMacroExpansion` while collecting `StartLocs` and `EndLocs`, > and stop once you hit a location where they return `false`. (That would mean > that you never step from the location of `AS1` out to the location of > `THING`.) Hmm. So I still run into the problem of none of the locations being at the start or end of the macro expansion. In your example, I only find 2 source locations at all. Let's say I have: ``` 1 #define AS1 __attribute__((address_space(1))) 2 3 int main() { 4 #define THING \ 5 int *p = 0; \ 6 AS1 int *q = p; 7 8 THING; 9 } ``` I only see the following expansion source locations: ``` /usr/local/google/home/leonardchan/misc/test.c:8:3 <Spelling=/usr/local/google/home/leonardchan/misc/test.c:1:13> /usr/local/google/home/leonardchan/misc/test.c:8:3 <Spelling=/usr/local/google/home/leonardchan/misc/test.c:6:3> ``` And it seems none of them return true for `isAtStartOfMacroExpansion` since the `__attribute__` keyword isn't the first token of `THING`. I imagine stopping early would work if the 2nd expansion location instead referred to `AS1` (on line 6 col 3), but it doesn't seem to be the case here. I can also see similar results for other examples where the macro is nested but does not encapsulate the whole macro: ``` #define THING2 int AS1 *q2 = p2; int *p2; THING2; // Error doesn't print AS1 ``` For our case, it seems like the correct thing to do is to get the spelling location and default to it if the macro itself doesn't contain the whole attribute. I updated and renamed this function to account for this and we can now see `AS1` printed. Also added test cases for this. For cases like `#define AS2 AS1`, `AS1` is still printed, but this is intended since `AS1` is more immediate of an expansion than `AS2`. ================ Comment at: clang/lib/Sema/SemaType.cpp:6967-6972 + QualType R = T.IgnoreParens().IgnoreMacroDefinitions(); while (const AttributedType *AT = dyn_cast<AttributedType>(R)) { if (AT->isCallingConv()) return true; - R = AT->getModifiedType().IgnoreParens(); + R = AT->getModifiedType().IgnoreParens().IgnoreMacroDefinitions(); } ---------------- rsmith wrote: > leonardchan wrote: > > rsmith wrote: > > > Instead of calling `IgnoreParens()` and `IgnoreMacroDefinitions` here, I > > > think we should just be ignoring any type sugar by using > > > `getAs<AttributedType>()`: > > > > > > ``` > > > bool Sema::hasExplicitCallingConv(QualType T) { > > > while (const auto *AT = T->getAs<AttributedType>()) { > > > if (AT->isCallingConv()) > > > return true; > > > T = AT->getModifiedType(); > > > } > > > return false; > > > } > > > ``` > > > > > > (Note also the change from passing `T` by reference -- and then never > > > storing to it in the function -- to passing it by value.) > > When using only `getAs`, the following 3 tests fail: > > > > Clang :: CodeGenCXX/mangle-ms.cpp > > Clang :: SemaCXX/calling-conv-compat.cpp > > Clang :: SemaCXX/decl-microsoft-call-conv.cpp > > > > since using `getAs` would involved removing a `TypeDefType` for each of > > these. Looking at the comment above this method's declaration, part of the > > intent is to retain the typedef sugar. We could still use `getAs` and not > > `IgnoreMacroDefinitions` by additionally checking for a typedef: > > > > ``` > > const AttributedType *AT; > > while ((AT = T->getAs<AttributedType>()) && !isa<TypedefType>(T)) { > > ``` > > > > Using `!T->getAs<TypedefType>()` will still fail for types laid out as: > > > > ``` > > AttributedType > > ` - TypedefType > > ``` > Can you give an example of the failures? The approach you're using here isn't > quite right, as it will skip over a `typedef` that's wrapped in another type > sugar node (when `T` is not a typedef but desugars to one). Something like > `&& AT->getAs<TypedefType>() == T->getAs<TypedefType>()` (that is: if we'd be > stripping off a `typedef` sugar node to reach the `AttributedType`, then > stop) should work, but maybe there's a better way to express that. Updated. Also there's just 1 error from each. This can be replicated just by using the new function and omitting the typedef check. CodeGenCXX/mangle-ms.cpp ``` /usr/local/google/home/leonardchan/llvm-monorepo/llvm-project-2/clang/test/CodeGenCXX/mangle-ms.cpp:386:15: error: CHECK-DAG: expected string not found in input // CHECK-DAG: ??2TypedefNewDelete@@SAPAXI@Z ``` SemaCXX/calling-conv-compat.cpp ``` error: 'error' diagnostics seen but not expected: File /usr/local/google/home/leonardchan/llvm-monorepo/llvm-project-2/clang/test/SemaCXX/calling-conv-compat.cpp Line 367: cannot initialize a variable of type 'MemberPointers::fun_cdecl MemberPointers::A::*' with an rvalue of type 'void (MemberPointers::A::*)() __attribute__((thiscall))' ``` SemaCXX/decl-microsoft-call-conv.cpp ``` error: 'error' diagnostics expected but not seen: File /usr/local/google/home/leonardchan/llvm-monorepo/llvm-project-2/clang/test/SemaCXX/decl-microsoft-call-conv.cpp Line 88: function declared 'cdecl' here was previously declared without calling convention ``` ================ Comment at: clang/lib/Sema/SemaType.cpp:7553-7560 + // Handle attributes that are defined in a macro. + if (attr.hasMacroIdentifier() && !type.getQualifiers().hasObjCLifetime()) { + const IdentifierInfo *MacroII = attr.getMacroIdentifier(); + if (FoundMacros.find(MacroII->getName()) == FoundMacros.end()) { + type = state.getSema().Context.getMacroDefinedType(type, MacroII); + FoundMacros.insert(MacroII->getName()); + } ---------------- rsmith wrote: > leonardchan wrote: > > rsmith wrote: > > > The handling (both here and in the parser) for a macro that defines > > > multiple attributes doesn't seem right. Given: > > > > > > ``` > > > #define ATTRS __attribute__((attr1, attr2)) > > > ATTRS int x; > > > ``` > > > > > > it looks like you'll end up with a type built as > > > > > > ``` > > > AttributedType attr1 > > > `- MacroDefinedType > > > `- AttributedType attr2 > > > `- int > > > ``` > > > > > > ... which seems wrong. > > > > > > > > > The parser representation also can't distinguish between the above case > > > and > > > > > > ``` > > > #define ATTRS __attribute__((attr1)) > > > ATTRS > > > #define ATTRS __attribute__((attr2)) > > > ATTRS > > > int x; > > > ``` > > > > > > ... since both will be represented as simply a macro identifier `ATTR` > > > attached to two different attributes (you could solve this by tracking > > > the source location of the expansion loc of the macro in the parsed > > > attribute representation, instead of or in addition to the macro > > > identifier). > > > > > > And the AST representation can't distinguish between the above and > > > > > > ``` > > > #define ATTRS __attribute__((attr1)) > > > ATTRS __attribute__((attr2)) int x; > > > ``` > > > > > > ... because it doesn't track what the modified type was, so we have to > > > guess which attributes are covered by the macro. > > > > > > Perhaps the best thing would be to support only the case of a macro that > > > expands to exactly one attribute for the initial commit, and add support > > > for macros covering multiple attributes as a follow-up commit? > > If it makes this cleaner and easier to review, I don't mind separating it > > into 2 patches with the first working for exactly one and the followup for > > multiple. For us though, we would mainly be using this for multiple > > attribute macros (especially `__attribute__((address_space(n), noderef))`. > > I can split it into 2 if you would like after this revision. > > > > As for the cases you presented, for > > > > ``` > > #define ATTRS __attribute__((attr1, attr2)) > > ATTRS int x; > > ``` > > > > I see that this prevents from adding any more `MacroQualifiedType`s for > > attributes that share the same name. Updated in this revision so that we > > continue to wrap `AttributedType`s, producing: > > > > ``` > > MacroQualifiedType (ATTRS) > > `- AttributedType attr1 > > ` - MacroQualifiedType (ATTRS) > > `- AttributedType attr2 > > `- int > > ``` > > > > In the case of > > > > ``` > > #define ATTRS __attribute__((attr1)) > > ATTRS > > #define ATTRS __attribute__((attr2)) > > ATTRS > > int x; > > ``` > > > > I added the expansion loc so we can distinguish between this and the first > > case now. > > > > As for > > > > ``` > > #define ATTRS __attribute__((attr1)) > > ATTRS __attribute__((attr2)) int x; > > ``` > > > > With this new revision, the AST representation now differs from the > > previous 2 examples in that only `attr1` gets wrapped with a > > `MacroQualifiedType` and not `attr2` producing: > > > > ``` > > AttributedType attr2 > > ` - MacroQualifiedType (ATTRS) > > `- AttributedType attr1 > > `- int > > ``` > > > > I also added test cases for these. > I think the ideal representation for this case would be > ``` > MacroQualifiedType (ATTRS) > `- AttributedType attr1 > `- AttributedType attr2 > `- int > ``` > ... but I can see that'll be a pain to produce. Let's go with your current > representation for now and look into improving it as a follow-up change. > (This'll give weird behavior in some cases: removing the outer > `AttributedType` will still lead to a type that pretty-prints as `ATTRS int`, > whereas it should pretty-print as `__attribute__((attr2)) int` because > `attr1` is not applied to the type.) Will do. ================ Comment at: clang/test/SemaObjC/gc-attributes.m:12-21 + f0(&a2); // expected-warning{{passing '__weak A **' to parameter of type '__strong A **' discards qualifiers}} } void f1(__weak A**); // expected-note{{passing argument to parameter here}} void test_f1() { A *a; ---------------- rsmith wrote: > This is wrong: we need to print the macro qualifier on the right in cases > like this so that it attaches to the pointer. You can use > `TypePrinter::canPrefixQualifier` to determine whether to print the macro > name on the left or the right. Fixed. I forgot to add a check for ObjCGCAttrs when creating the type. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D51329/new/ https://reviews.llvm.org/D51329 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits