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, + const IdentifierInfo *MacroII); QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, QualType Replacement) const; Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -4315,13 +4315,18 @@ QualType ModifiedType; QualType EquivalentType; + // If the attribute this type holds was declared entirely in a macro, we store + // the macro identifier information. This can be used for printing the macro + // name instead of the attribute. + const IdentifierInfo *MacroII; + AttributedType(QualType canon, attr::Kind attrKind, QualType modified, - QualType equivalent) + QualType equivalent, const IdentifierInfo *macroII) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), equivalent->isVariablyModifiedType(), equivalent->containsUnexpandedParameterPack()), - ModifiedType(modified), EquivalentType(equivalent) { + ModifiedType(modified), EquivalentType(equivalent), MacroII(macroII) { AttributedTypeBits.AttrKind = attrKind; } @@ -4333,6 +4338,11 @@ QualType getModifiedType() const { return ModifiedType; } QualType getEquivalentType() const { return EquivalentType; } + /// Retrieve the type macro identifier info object that this type was created + /// with (if available). + const IdentifierInfo *getMacroIdentifier() const { return MacroII; } + bool hasMacroIdentifier() const { return MacroII != nullptr; } + bool isSugared() const { return true; } QualType desugar() const { return getEquivalentType(); } @@ -4387,14 +4397,16 @@ static Optional stripOuterNullability(QualType &T); void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAttrKind(), ModifiedType, EquivalentType); + Profile(ID, getAttrKind(), ModifiedType, EquivalentType, MacroII); } static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, - QualType modified, QualType equivalent) { + QualType modified, QualType equivalent, + const IdentifierInfo *macroII) { ID.AddInteger(attrKind); ID.AddPointer(modified.getAsOpaquePtr()); ID.AddPointer(equivalent.getAsOpaquePtr()); + ID.AddPointer(macroII); } static bool classof(const Type *T) { Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1114,6 +1114,7 @@ Parser *Self; CachedTokens Toks; IdentifierInfo &AttrName; + IdentifierInfo *MacroII = nullptr; SourceLocation AttrNameLoc; SmallVector Decls; Index: include/clang/Sema/ParsedAttr.h =================================================================== --- include/clang/Sema/ParsedAttr.h +++ include/clang/Sema/ParsedAttr.h @@ -168,6 +168,7 @@ private: IdentifierInfo *AttrName; IdentifierInfo *ScopeName; + IdentifierInfo *MacroII = nullptr; SourceRange AttrRange; SourceLocation ScopeLoc; SourceLocation EllipsisLoc; @@ -534,6 +535,17 @@ return getPropertyDataBuffer().SetterId; } + /// Set the macro identifier info object that this parsed attribute was + /// declared in if it was declared in a macro. + void setMacroIdentifier(IdentifierInfo *MacroName) { MacroII = MacroName; } + + /// Returns true if this attribute was declared in a macro. + bool hasMacroIdentifier() const { return MacroII != nullptr; } + + /// Return the macro identifier if this attribute was declared in a macro. + /// nullptr is returned if it was not declared in a macro. + IdentifierInfo *getMacroIdentifier() const { return MacroII; } + /// Get an index into the attribute spelling list /// defined in Attr.td. This index is used by an attribute /// to pretty print itself. Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -2708,7 +2708,8 @@ return getAttributedType( AT->getAttrKind(), getFunctionTypeWithExceptionSpec(AT->getModifiedType(), ESI), - getFunctionTypeWithExceptionSpec(AT->getEquivalentType(), ESI)); + getFunctionTypeWithExceptionSpec(AT->getEquivalentType(), ESI), + AT->getMacroIdentifier()); // Anything else must be a function type. Rebuild it with the new exception // specification. @@ -3878,9 +3879,10 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind, QualType modifiedType, - QualType equivalentType) { + QualType equivalentType, + const 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); @@ -3888,7 +3890,7 @@ 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); @@ -5461,7 +5463,8 @@ // int x[_Nullable] -> int * _Nullable if (auto Nullability = Ty->getNullability(*this)) { Result = const_cast(this)->getAttributedType( - AttributedType::getNullabilityAttrKind(*Nullability), Result, Result); + AttributedType::getNullabilityAttrKind(*Nullability), Result, Result, + Ty->getAs()->getMacroIdentifier()); } return Result; } Index: lib/AST/ASTDiagnostic.cpp =================================================================== --- lib/AST/ASTDiagnostic.cpp +++ lib/AST/ASTDiagnostic.cpp @@ -74,7 +74,8 @@ QualType RT = Desugar(Context, SugarRT, DesugarReturn); if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) { RT = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*nullability), RT, RT); + AttributedType::getNullabilityAttrKind(*nullability), RT, RT, + FT->getReturnType()->getAs()->getMacroIdentifier()); } bool DesugarArgument = false; @@ -83,10 +84,12 @@ if (FPT) { for (QualType SugarPT : FPT->param_types()) { QualType PT = Desugar(Context, SugarPT, DesugarArgument); + QualType OldSugarPT = SugarPT; if (auto nullability = AttributedType::stripOuterNullability(SugarPT)) { PT = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*nullability), PT, PT); + AttributedType::getNullabilityAttrKind(*nullability), PT, PT, + OldSugarPT->getAs()->getMacroIdentifier()); } Args.push_back(PT); } Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -986,8 +986,9 @@ return {}; } - return Importer.getToContext().getAttributedType(T->getAttrKind(), - ToModifiedType, ToEquivalentType); + return Importer.getToContext().getAttributedType( + T->getAttrKind(), ToModifiedType, ToEquivalentType, + T->getMacroIdentifier()); } QualType ASTNodeImporter::VisitTemplateTypeParmType( Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -1004,8 +1004,8 @@ == T->getEquivalentType().getAsOpaquePtr()) return QualType(T, 0); - return Ctx.getAttributedType(T->getAttrKind(), modifiedType, - equivalentType); + return Ctx.getAttributedType(T->getAttrKind(), modifiedType, equivalentType, + T->getMacroIdentifier()); } QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1364,7 +1364,18 @@ if (T->getAttrKind() == attr::ObjCKindOf) OS << "__kindof "; - printBefore(T->getModifiedType(), OS); + if (T->getAttrKind() == attr::AddressSpace && T->hasMacroIdentifier()) { + OS << T->getMacroIdentifier()->getName() << " "; + + // Remove the underlying address_space so it won't be printed. + SplitQualType SplitTy = T->getModifiedType().split(); + Qualifiers Quals = SplitTy.Quals; + if (Quals.getAddressSpace() >= LangAS::FirstTargetAddressSpace) + Quals.removeAddressSpace(); + printBefore(SplitTy.Ty, Quals, OS); + } else { + printBefore(T->getModifiedType(), OS); + } if (T->isMSTypeSpec()) { switch (T->getAttrKind()) { Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -135,6 +135,10 @@ assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); while (Tok.is(tok::kw___attribute)) { + Token AttrTok = Tok; + unsigned OldNumAttrs = attrs.size(); + unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0; + ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "attribute")) { @@ -203,6 +207,35 @@ SkipUntil(tok::r_paren, StopAtSemi); if (endLoc) *endLoc = Loc; + + // If this was declared in a macro, attatch the macro IdentifierInfo to the + // parsed attribute. + SourceLocation AttrTokLoc = AttrTok.getLocation(); + auto &SrcMgr = PP.getSourceManager(); + bool AttrStartIsInMacro = + (AttrTokLoc.isMacroID() && Lexer::isAtStartOfMacroExpansion( + AttrTokLoc, SrcMgr, PP.getLangOpts())); + bool AttrEndIsInMacro = + (Loc.isMacroID() && + Lexer::isAtEndOfMacroExpansion(Loc, SrcMgr, PP.getLangOpts())); + bool WholeAttrIsInMacro = + (AttrStartIsInMacro && AttrEndIsInMacro && + SrcMgr.getExpansionLoc(AttrTokLoc) == SrcMgr.getExpansionLoc(Loc)); + + if (WholeAttrIsInMacro) { + StringRef name = Lexer::getSourceText( + SrcMgr.getExpansionRange(AttrTokLoc), SrcMgr, PP.getLangOpts()); + IdentifierInfo *MacroII = PP.getIdentifierInfo(name); + + for (unsigned i = OldNumAttrs; i < attrs.size(); ++i) + attrs[i].setMacroIdentifier(MacroII); + + if (LateAttrs) { + for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i) { + (*LateAttrs)[i]->MacroII = MacroII; + } + } + } } } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2784,8 +2784,8 @@ } else { QualType NewT = NewParam->getType(); NewT = S.Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*Oldnullability), - NewT, NewT); + AttributedType::getNullabilityAttrKind(*Oldnullability), NewT, NewT, + OldParam->getType()->getAs()->getMacroIdentifier()); NewParam->setType(NewT); } } Index: lib/Sema/SemaDeclObjC.cpp =================================================================== --- lib/Sema/SemaDeclObjC.cpp +++ lib/Sema/SemaDeclObjC.cpp @@ -4428,8 +4428,8 @@ // Otherwise, provide the result with the same nullability. return S.Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*prevNullability), - type, type); + AttributedType::getNullabilityAttrKind(*prevNullability), type, type, + nullptr); } /// Merge information from the declaration of a method in the \@interface Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7266,7 +7266,7 @@ // Create a new AttributedType with the new nullability kind. auto NewAttr = AttributedType::getNullabilityAttrKind(MergedKind); - return Ctx.getAttributedType(NewAttr, ResTy, ResTy); + return Ctx.getAttributedType(NewAttr, ResTy, ResTy, nullptr); } /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null Index: lib/Sema/SemaExprObjC.cpp =================================================================== --- lib/Sema/SemaExprObjC.cpp +++ lib/Sema/SemaExprObjC.cpp @@ -569,7 +569,10 @@ if (Nullability) BoxedType = Context.getAttributedType( AttributedType::getNullabilityAttrKind(*Nullability), BoxedType, - BoxedType); + BoxedType, + BoxingMethod->getReturnType() + ->getAs() + ->getMacroIdentifier()); } } else if (ValueType->isBuiltinType()) { // The other types we support are numeric, char and BOOL/bool. We could also @@ -1262,9 +1265,9 @@ if (auto nullability = AttributedType::stripOuterNullability(T)) { if (T == Context.getObjCInstanceType()) { return Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*nullability), - Context.getObjCIdType(), - Context.getObjCIdType()); + AttributedType::getNullabilityAttrKind(*nullability), + Context.getObjCIdType(), Context.getObjCIdType(), + origType->getAs()->getMacroIdentifier()); } return origType; @@ -1296,16 +1299,15 @@ // result type to the returned result. auto transferNullability = [&](QualType type) -> QualType { // If the method's result type has nullability, extract it. - if (auto nullability = Method->getSendResultType(ReceiverType) - ->getNullability(Context)){ + QualType MethodResultTy = Method->getSendResultType(ReceiverType); + if (auto nullability = MethodResultTy->getNullability(Context)) { // Strip off any outer nullability sugar from the provided type. (void)AttributedType::stripOuterNullability(type); // Form a new attributed type using the method result type's nullability. return Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*nullability), - type, - type); + AttributedType::getNullabilityAttrKind(*nullability), type, type, + MethodResultTy->getAs()->getMacroIdentifier()); } return type; @@ -1408,8 +1410,8 @@ auto newNullability = static_cast(newResultNullabilityIdx-1); return Context.getAttributedType( - AttributedType::getNullabilityAttrKind(newNullability), - resultType, resultType); + AttributedType::getNullabilityAttrKind(newNullability), resultType, + resultType, nullptr); } return resultType; Index: lib/Sema/SemaObjCProperty.cpp =================================================================== --- lib/Sema/SemaObjCProperty.cpp +++ lib/Sema/SemaObjCProperty.cpp @@ -2384,8 +2384,9 @@ QualType modifiedTy = resultTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) { if (*nullability == NullabilityKind::Unspecified) - resultTy = Context.getAttributedType(attr::TypeNonNull, - modifiedTy, modifiedTy); + resultTy = Context.getAttributedType( + attr::TypeNonNull, modifiedTy, modifiedTy, + resultTy->getAs()->getMacroIdentifier()); } } @@ -2458,8 +2459,9 @@ QualType modifiedTy = paramTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){ if (*nullability == NullabilityKind::Unspecified) - paramTy = Context.getAttributedType(attr::TypeNullable, - modifiedTy, modifiedTy); + paramTy = Context.getAttributedType( + attr::TypeNullable, modifiedTy, modifiedTy, + paramTy->getAs()->getMacroIdentifier()); } } Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -243,9 +243,9 @@ /// 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); + QualType EquivType, IdentifierInfo *MacroII) { + QualType T = sema.Context.getAttributedType(A->getKind(), ModifiedType, + EquivType, MacroII); AttrsForTypes.push_back({cast(T.getTypePtr()), A}); AttrsForTypesSorted = false; return T; @@ -4258,7 +4258,8 @@ D.getDeclSpec().getEndLoc(), D.getMutableDeclSpec().getAttributes())) { T = state.getAttributedType( - createNullabilityAttr(Context, *attr, *inferNullability), T, T); + createNullabilityAttr(Context, *attr, *inferNullability), T, T, + attr->getMacroIdentifier()); } } } @@ -5817,7 +5818,7 @@ auto *ASAttr = ::new (Ctx) AddressSpaceAttr( Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), static_cast(T.getQualifiers().getAddressSpace())); - Type = State.getAttributedType(ASAttr, T, T); + Type = State.getAttributedType(ASAttr, T, T, Attr.getMacroIdentifier()); } else { Attr.setInvalid(); } @@ -6012,8 +6013,8 @@ if (!S.getLangOpts().ObjCAutoRefCount && lifetime == Qualifiers::OCL_ExplicitNone) { type = state.getAttributedType( - createSimpleAttr(S.Context, attr), - type, type); + createSimpleAttr(S.Context, attr), type, + type, attr.getMacroIdentifier()); return true; } @@ -6027,7 +6028,7 @@ type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr( attr.getRange(), S.Context, II, attr.getAttributeSpellingListIndex()), - origType, type); + origType, type, attr.getMacroIdentifier()); } auto diagnoseOrDelay = [](Sema &S, SourceLocation loc, @@ -6131,7 +6132,7 @@ type = state.getAttributedType( ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II, attr.getAttributeSpellingListIndex()), - origType, type); + origType, type, attr.getMacroIdentifier()); return true; } @@ -6341,7 +6342,7 @@ return true; } - Type = State.getAttributedType(A, Type, Type); + Type = State.getAttributedType(A, Type, Type, PAttr.getMacroIdentifier()); return false; } @@ -6473,7 +6474,8 @@ // Form the attributed type. type = state.getAttributedType( - createNullabilityAttr(S.Context, attr, nullability), type, type); + createNullabilityAttr(S.Context, attr, nullability), type, type, + attr.getMacroIdentifier()); return false; } @@ -6486,7 +6488,8 @@ if (isa(type)) { // Build the attributed type to record where __kindof occurred. type = state.getAttributedType( - createSimpleAttr(S.Context, attr), type, type); + createSimpleAttr(S.Context, attr), type, type, + attr.getMacroIdentifier()); return false; } @@ -6521,13 +6524,15 @@ "multiple spellings for __kindof?"); Attr *A = createNullabilityAttr(S.Context, attr, *nullability); A->setImplicit(true); - equivType = state.getAttributedType(A, equivType, equivType); + equivType = state.getAttributedType(A, equivType, equivType, + attr.getMacroIdentifier()); } } // Build the attributed type to record where __kindof occurred. - type = state.getAttributedType( - createSimpleAttr(S.Context, attr), type, equivType); + type = + state.getAttributedType(createSimpleAttr(S.Context, attr), + type, equivType, attr.getMacroIdentifier()); return false; } @@ -6712,8 +6717,8 @@ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); } type = state.getAttributedType( - createSimpleAttr(S.Context, attr), - origType, type); + createSimpleAttr(S.Context, attr), origType, + type, attr.getMacroIdentifier()); return true; } @@ -6847,7 +6852,8 @@ Equivalent = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); } - type = state.getAttributedType(CCAttr, type, Equivalent); + type = state.getAttributedType(CCAttr, type, Equivalent, + attr.getMacroIdentifier()); return true; } @@ -7209,7 +7215,7 @@ if (State.getDeclarator().isDeclarationOfFunction()) { CurType = State.getAttributedType( createSimpleAttr(State.getSema().Context, Attr), - CurType, CurType); + CurType, CurType, Attr.getMacroIdentifier()); } else { Attr.diagnoseAppertainsTo(State.getSema(), nullptr); } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -6087,9 +6087,9 @@ } } - result = SemaRef.Context.getAttributedType(TL.getAttrKind(), - modifiedType, - equivalentType); + result = SemaRef.Context.getAttributedType(TL.getAttrKind(), modifiedType, + equivalentType, + oldType->getMacroIdentifier()); } AttributedTypeLoc newTL = TLB.push(result); Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6168,14 +6168,16 @@ } case TYPE_ATTRIBUTED: { - if (Record.size() != 3) { + if (Record.size() != 4) { Error("incorrect encoding of attributed type"); return QualType(); } QualType modifiedType = readType(*Loc.F, Record, Idx); QualType equivalentType = readType(*Loc.F, Record, Idx); AttributedType::Kind kind = static_cast(Record[2]); - return Context.getAttributedType(kind, modifiedType, equivalentType); + IdentifierInfo *MacroII = GetIdentifierInfo(*Loc.F, Record, Idx); + return Context.getAttributedType(kind, modifiedType, equivalentType, + MacroII); } case TYPE_PAREN: { Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -404,6 +404,7 @@ Record.AddTypeRef(T->getModifiedType()); Record.AddTypeRef(T->getEquivalentType()); Record.push_back(T->getAttrKind()); + Record.AddIdentifierRef(T->getMacroIdentifier()); Code = TYPE_ATTRIBUTED; } Index: test/Sema/address_space_print_macro.c =================================================================== --- /dev/null +++ test/Sema/address_space_print_macro.c @@ -0,0 +1,39 @@ +// 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))) + +#define ATTR __attribute__ +#define AS4 ATTR((AS(4))) +#define AS5 __attribute__((address_space(5))) char + +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; + AS4 char *x3; + AS5 *x4; + 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}} + y = x3; // expected-error{{assigning 'AS4 char *' to 'char *' changes address space of pointer}} + y = x4; // expected-error{{assigning '__attribute__((address_space(5))) char *' to 'char *' changes address space of pointer}} +} 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}} }