leonardchan added inline comments.

================
Comment at: clang/lib/AST/Type.cpp:382-386
+QualType QualType::IgnoreMacroDefinitions(QualType T) {
+  while (const auto *MDT = T->getAs<MacroDefinedType>())
+    T = MDT->getUnderlyingType();
+  return T;
+}
----------------
rsmith wrote:
> This doesn't seem like a sufficiently general operation to warrant being a 
> member of `QualType` to me, and like `IgnoreParens` before it, this is wrong 
> with regard to qualifiers (it drops top-level qualifiers on the type if 
> they're outside the macro qualifier). Looking through the uses below, I think 
> there are better ways to write them that avoid the need for this function.
Removed this method.


================
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:
> 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.


================
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:
> 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
```


================
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:
> 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.


Repository:
  rC Clang

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

Reply via email to