leonardchan updated this revision to Diff 162966.
leonardchan marked 3 inline comments as done.
Repository:
rC Clang
https://reviews.llvm.org/D51329
Files:
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/Lex/Preprocessor.h
lib/AST/ASTContext.cpp
lib/AST/TypePrinter.cpp
lib/Lex/PPDirectives.cpp
lib/Sema/SemaType.cpp
test/Sema/address_space_print_macro.c
test/Sema/address_spaces.c
Index: test/Sema/address_spaces.c
===================================================================
--- test/Sema/address_spaces.c
+++ test/Sema/address_spaces.c
@@ -71,5 +71,5 @@
// Clang extension doesn't forbid operations on pointers to different address spaces.
char* cmp(_AS1 char *x, _AS2 char *y) {
- return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *') which are pointers to non-overlapping address spaces}}
+ return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}}
}
Index: test/Sema/address_space_print_macro.c
===================================================================
--- /dev/null
+++ test/Sema/address_space_print_macro.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+
+#define AS1 __attribute__((address_space(1)))
+#define AS2 __attribute__((address_space(2), annotate("foo")))
+
+#define AS(i) address_space(i)
+#define AS3 __attribute__((AS(3)))
+
+char *cmp(AS1 char *x, AS2 char *y) {
+ return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('AS1 char *' and 'AS2 char *') which are pointers to non-overlapping address spaces}}
+}
+
+__attribute__((address_space(1))) char test_array[10];
+void test3(void) {
+ extern void test3_helper(char *p); // expected-note{{passing argument to parameter 'p' here}}
+ test3_helper(test_array); // expected-error{{passing '__attribute__((address_space(1))) char *' to parameter of type 'char *' changes address space of pointer}}
+}
+
+char AS2 *test4_array;
+void test4(void) {
+ extern void test3_helper(char *p); // expected-note{{passing argument to parameter 'p' here}}
+ test3_helper(test4_array); // expected-error{{passing 'AS2 char *' to parameter of type 'char *' changes address space of pointer}}
+}
+
+void func() {
+ char AS1 *x;
+ char AS3 *x2;
+ char *y;
+ y = x; // expected-error{{assigning 'AS1 char *' to 'char *' changes address space of pointer}}
+ y = x2; // expected-error{{assigning 'AS3 char *' to 'char *' changes address space of pointer}}
+}
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -240,12 +240,60 @@
diagnoseBadTypeAttribute(getSema(), *Attr, type);
}
+ static bool SourceLocInSourceRange(SourceLocation SpellingLoc,
+ SourceRange Range,
+ const SourceManager &SM) {
+ SourceLocation RangeStart = Range.getBegin();
+ SourceLocation RangeEnd = Range.getEnd();
+ unsigned LineNo = SM.getSpellingLineNumber(SpellingLoc);
+ unsigned StartLineNo = SM.getSpellingLineNumber(RangeStart);
+ unsigned EndLineNo = SM.getSpellingLineNumber(RangeEnd);
+ unsigned ColNo = SM.getSpellingColumnNumber(SpellingLoc);
+ unsigned StartColNo = SM.getSpellingColumnNumber(RangeStart);
+ unsigned EndColNo = SM.getSpellingColumnNumber(RangeEnd);
+
+ // Outside of lines
+ if (LineNo < StartLineNo || LineNo > EndLineNo)
+ return false;
+
+ // On the same line
+ if (LineNo == StartLineNo && ColNo < StartColNo)
+ return false;
+ if (LineNo == EndLineNo && ColNo > EndColNo)
+ return false;
+
+ return true;
+ }
+
/// Get an attributed type for the given attribute, and remember the Attr
/// object so that we can attach it to the AttributedTypeLoc.
QualType getAttributedType(Attr *A, QualType ModifiedType,
QualType EquivType) {
- QualType T =
- sema.Context.getAttributedType(A->getKind(), ModifiedType, EquivType);
+ IdentifierInfo *MacroII = nullptr;
+ SourceLocation start = A->getRange().getBegin();
+ if (start.isMacroID()) {
+ // Walk the macro expansion
+ SourceLocation Loc = start;
+ auto &SM = sema.SourceMgr;
+ while (Loc.isMacroID() && !MacroII) {
+ for (const auto &MacroPair : sema.PP.getAttributeMacros()) {
+ SourceRange Range = MacroPair.first;
+ if (SourceLocInSourceRange(Loc, Range, sema.SourceMgr)) {
+ // Found the attribute declared in a macro.
+ MacroII = MacroPair.second;
+ break;
+ }
+ }
+
+ FileID FID = SM.getFileID(Loc);
+ const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
+ const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+ Loc = Expansion.getExpansionLocStart();
+ }
+ }
+
+ QualType T = sema.Context.getAttributedType(A->getKind(), ModifiedType,
+ EquivType, MacroII);
AttrsForTypes.push_back({cast<AttributedType>(T.getTypePtr()), A});
AttrsForTypesSorted = false;
return T;
Index: lib/Lex/PPDirectives.cpp
===================================================================
--- lib/Lex/PPDirectives.cpp
+++ lib/Lex/PPDirectives.cpp
@@ -2577,6 +2577,31 @@
MI->setDefinitionEndLoc(LastTok.getLocation());
return MI;
}
+
+// The minimum number of tokens used for an attribute. This includes the
+// attribute keyword, 2 opening parentheses, 2 closing parenthesis, and at least
+// one token for the attribute itself.
+static constexpr unsigned kMinAttrTokens = 6;
+
+/// This only catches macros whose whole definition is an attribute. That is, it
+/// starts with the attribute keyword and 2 opening parentheses, and ends with
+/// the 2 closing parentheses.
+static bool DefinesAttribute(const Preprocessor &PP,
+ const ArrayRef<Token> &Tokens,
+ SourceRange &Range) {
+ if (Tokens.size() < kMinAttrTokens)
+ return false;
+ if (Tokens[0].is(tok::kw___attribute) && Tokens[1].is(tok::l_paren) &&
+ Tokens[2].is(tok::l_paren) &&
+ Tokens[Tokens.size() - 2].is(tok::r_paren) &&
+ Tokens[Tokens.size() - 1].is(tok::r_paren)) {
+ Range.setBegin(Tokens.front().getLocation());
+ Range.setEnd(Tokens.back().getLocation());
+ return true;
+ }
+ return false;
+}
+
/// HandleDefineDirective - Implements \#define. This consumes the entire macro
/// line then lets the caller lex the next real token.
void Preprocessor::HandleDefineDirective(
@@ -2692,6 +2717,13 @@
WarnUnusedMacroLocs.insert(MI->getDefinitionLoc());
}
+ // If the macro is an attribute that contains address_space(), save this for
+ // diagnosing later.
+ SourceRange Range;
+ if (DefinesAttribute(*this, MD->getInfo()->tokens(), Range))
+ AttributeMacros.push_back(
+ std::make_pair(Range, MacroNameTok.getIdentifierInfo()));
+
// If the callbacks want to know, tell them about the macro definition.
if (Callbacks)
Callbacks->MacroDefined(MacroNameTok, MD);
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -1364,7 +1364,12 @@
if (T->getAttrKind() == attr::ObjCKindOf)
OS << "__kindof ";
- printBefore(T->getModifiedType(), OS);
+ if (T->getAttrKind() == attr::AddressSpace && T->hasAddressSpaceMacroII()) {
+ OS << T->getAddressSpaceMacroII()->getName() << " ";
+ printBefore(T->getModifiedType().getUnqualifiedType(), OS);
+ } else {
+ printBefore(T->getModifiedType(), OS);
+ }
if (T->isMSTypeSpec()) {
switch (T->getAttrKind()) {
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -3878,17 +3878,18 @@
QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType modifiedType,
- QualType equivalentType) {
+ QualType equivalentType,
+ IdentifierInfo *MacroII) {
llvm::FoldingSetNodeID id;
- AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
+ AttributedType::Profile(id, attrKind, modifiedType, equivalentType, MacroII);
void *insertPos = nullptr;
AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
if (type) return QualType(type, 0);
QualType canon = getCanonicalType(equivalentType);
type = new (*this, TypeAlignment)
- AttributedType(canon, attrKind, modifiedType, equivalentType);
+ AttributedType(canon, attrKind, modifiedType, equivalentType, MacroII);
Types.push_back(type);
AttributedTypes.InsertNode(type, insertPos);
Index: include/clang/Lex/Preprocessor.h
===================================================================
--- include/clang/Lex/Preprocessor.h
+++ include/clang/Lex/Preprocessor.h
@@ -325,6 +325,9 @@
/// This is used when loading a precompiled preamble.
std::pair<int, bool> SkipMainFilePreamble;
+ typedef std::pair<SourceRange, IdentifierInfo *> MacroPair;
+ llvm::SmallVector<MacroPair, 8> AttributeMacros;
+
public:
struct PreambleSkipInfo {
SourceLocation HashTokenLoc;
@@ -341,6 +344,10 @@
ElseLoc(ElseLoc) {}
};
+ const llvm::SmallVectorImpl<MacroPair> &getAttributeMacros() const {
+ return AttributeMacros;
+ }
+
private:
friend class ASTReader;
friend class MacroArgs;
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -4315,13 +4315,21 @@
QualType ModifiedType;
QualType EquivalentType;
+ // If the attribute this type holds is address_space and this attribute was
+ // declared as part of a macro, we store the macro identifier information.
+ // This will be used for printing the macro name instead of
+ // `__attribute__((address_space(n)))` in diagnostics relating to differing
+ // address_spaces between types.
+ IdentifierInfo *AddressSpaceMacroII;
+
AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
- QualType equivalent)
+ QualType equivalent, IdentifierInfo *addrSpaceMacroII)
: Type(Attributed, canon, equivalent->isDependentType(),
equivalent->isInstantiationDependentType(),
equivalent->isVariablyModifiedType(),
equivalent->containsUnexpandedParameterPack()),
- ModifiedType(modified), EquivalentType(equivalent) {
+ ModifiedType(modified), EquivalentType(equivalent),
+ AddressSpaceMacroII(addrSpaceMacroII) {
AttributedTypeBits.AttrKind = attrKind;
}
@@ -4332,6 +4340,8 @@
QualType getModifiedType() const { return ModifiedType; }
QualType getEquivalentType() const { return EquivalentType; }
+ IdentifierInfo *getAddressSpaceMacroII() const { return AddressSpaceMacroII; }
+ bool hasAddressSpaceMacroII() const { return AddressSpaceMacroII != nullptr; }
bool isSugared() const { return true; }
QualType desugar() const { return getEquivalentType(); }
@@ -4387,14 +4397,17 @@
static Optional<NullabilityKind> stripOuterNullability(QualType &T);
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAttrKind(), ModifiedType, EquivalentType);
+ Profile(ID, getAttrKind(), ModifiedType, EquivalentType,
+ AddressSpaceMacroII);
}
static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
- QualType modified, QualType equivalent) {
+ QualType modified, QualType equivalent,
+ IdentifierInfo *addrSpaceMacroII) {
ID.AddInteger(attrKind);
ID.AddPointer(modified.getAsOpaquePtr());
ID.AddPointer(equivalent.getAsOpaquePtr());
+ ID.AddPointer(addrSpaceMacroII);
}
static bool classof(const Type *T) {
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1423,9 +1423,9 @@
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
- QualType getAttributedType(attr::Kind attrKind,
- QualType modifiedType,
- QualType equivalentType);
+ QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
+ QualType equivalentType,
+ IdentifierInfo *MacroII = nullptr);
QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
QualType Replacement) const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits