Skip to content

Commit 4bb0980

Browse files
committedFeb 10, 2014
MS ABI: Add support for #pragma pointers_to_members
Introduce a notion of a 'current representation method' for pointers-to-members. When starting out, this is set to 'best case' (representation method is chosen by examining the class, selecting the smallest representation that would work given the class definition or lack thereof). This pragma allows the translation unit to dictate exactly what representation to use, similar to how the inheritance model keywords operate. N.B. PCH support is forthcoming. Differential Revision: http://llvm-reviews.chandlerc.com/D2723 llvm-svn: 201105
1 parent 756c22c commit 4bb0980

19 files changed

+250
-23
lines changed
 

‎clang/include/clang/AST/DeclCXX.h

-2
Original file line numberDiff line numberDiff line change
@@ -1600,8 +1600,6 @@ class CXXRecordDecl : public RecordDecl {
16001600

16011601
/// \brief Returns the inheritance model used for this record.
16021602
MSInheritanceAttr::Spelling getMSInheritanceModel() const;
1603-
/// \brief Locks-in the inheritance model for this class.
1604-
void setMSInheritanceModel();
16051603
/// \brief Calculate what the inheritance model would be for this class.
16061604
MSInheritanceAttr::Spelling calculateInheritanceModel() const;
16071605

‎clang/include/clang/Basic/Attr.td

+6
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
9999
// be dependent.
100100
class AlignedArgument<string name, bit opt = 0> : Argument<name, opt>;
101101

102+
// A bool argument with a default value
103+
class DefaultBoolArgument<string name, bit default> : BoolArgument<name, 1> {
104+
bit Default = default;
105+
}
106+
102107
// An integer argument with a default value
103108
class DefaultIntArgument<string name, int default> : IntArgument<name, 1> {
104109
int Default = default;
@@ -1397,6 +1402,7 @@ def UPtr : TypeAttr {
13971402

13981403
def MSInheritance : InheritableAttr {
13991404
let LangOpts = [MicrosoftExt];
1405+
let Args = [DefaultBoolArgument<"BestCase", 1>];
14001406
let Spellings = [Keyword<"__single_inheritance">,
14011407
Keyword<"__multiple_inheritance">,
14021408
Keyword<"__virtual_inheritance">,

‎clang/include/clang/Basic/DiagnosticParseKinds.td

+6
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ def err_invalid_token_after_declarator_suggest_equal : Error<
177177
"invalid %0 at end of declaration; did you mean '='?">;
178178
def err_expected_statement : Error<"expected statement">;
179179
def err_expected_lparen_after : Error<"expected '(' after '%0'">;
180+
def err_expected_rparen_after : Error<"expected ')' after '%0'">;
181+
def err_expected_punc : Error<"expected ')' or ',' after '%0'">;
180182
def err_expected_less_after : Error<"expected '<' after '%0'">;
181183
def err_expected_lbrace_in_compound_literal : Error<
182184
"expected '{' in compound literal">;
@@ -809,6 +811,10 @@ def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
809811
def err_pragma_detect_mismatch_malformed : Error<
810812
"pragma detect_mismatch is malformed; it requires two comma-separated "
811813
"string literals">;
814+
// - #pragma pointers_to_members
815+
def err_pragma_pointers_to_members_unknown_kind : Error<
816+
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
817+
"'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'">;
812818

813819
// OpenCL Section 6.8.g
814820
def err_not_opencl_storage_class_specifier : Error<

‎clang/include/clang/Basic/TokenKinds.def

+5
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,11 @@ ANNOTATION(pragma_redefine_extname)
673673
// handles them.
674674
ANNOTATION(pragma_fp_contract)
675675

676+
// Annotation for #pragma pointers_to_members...
677+
// The lexer produces these so that they only take effect when the parser
678+
// handles them.
679+
ANNOTATION(pragma_ms_pointers_to_members)
680+
676681
// Annotation for #pragma OPENCL EXTENSION...
677682
// The lexer produces these so that they only take effect when the parser
678683
// handles them.

‎clang/include/clang/Parse/Parser.h

+3
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class Parser : public CodeCompletionHandler {
155155
OwningPtr<PragmaHandler> OpenMPHandler;
156156
OwningPtr<PragmaHandler> MSCommentHandler;
157157
OwningPtr<PragmaHandler> MSDetectMismatchHandler;
158+
OwningPtr<PragmaHandler> MSPointersToMembers;
158159

159160
/// Whether the '>' token acts as an operator or not. This will be
160161
/// true except when we are parsing an expression within a C++
@@ -457,6 +458,8 @@ class Parser : public CodeCompletionHandler {
457458
/// #pragma comment...
458459
void HandlePragmaMSComment();
459460

461+
void HandlePragmaMSPointersToMembers();
462+
460463
/// \brief Handle the annotation token produced for
461464
/// #pragma align...
462465
void HandlePragmaAlign();

‎clang/include/clang/Sema/Sema.h

+21-2
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,19 @@ class Sema {
262262

263263
bool MSStructPragmaOn; // True when \#pragma ms_struct on
264264

265+
enum PragmaMSPointersToMembersKind {
266+
PPTMK_BestCase,
267+
PPTMK_FullGeneralitySingleInheritance,
268+
PPTMK_FullGeneralityMultipleInheritance,
269+
PPTMK_FullGeneralityVirtualInheritance,
270+
};
271+
272+
/// \brief Controls member pointer representation format under the MS ABI.
273+
PragmaMSPointersToMembersKind MSPointerToMemberRepresentationMethod;
274+
275+
/// \brief Source location for newly created implicit MSInheritanceAttrs
276+
SourceLocation ImplicitMSInheritanceAttrLoc;
277+
265278
/// VisContext - Manages the stack for \#pragma GCC visibility.
266279
void *VisContext; // Really a "PragmaVisStack*"
267280

@@ -1864,7 +1877,7 @@ class Sema {
18641877
DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range,
18651878
unsigned AttrSpellingListIndex);
18661879
MSInheritanceAttr *
1867-
mergeMSInheritanceAttr(Decl *D, SourceRange Range,
1880+
mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase,
18681881
unsigned AttrSpellingListIndex,
18691882
MSInheritanceAttr::Spelling SemanticSpelling);
18701883
FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range,
@@ -2577,7 +2590,7 @@ class Sema {
25772590
unsigned ArgNum, StringRef &Str,
25782591
SourceLocation *ArgLocation = 0);
25792592
bool checkMSInheritanceAttrOnDefinition(
2580-
CXXRecordDecl *RD, SourceRange Range,
2593+
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
25812594
MSInheritanceAttr::Spelling SemanticSpelling);
25822595

25832596
void CheckAlignasUnderalignment(Decl *D);
@@ -6970,6 +6983,12 @@ class Sema {
69706983
/// \#pragma comment(kind, "arg").
69716984
void ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg);
69726985

6986+
/// ActOnPragmaMSPointersToMembers - called on well formed \#pragma
6987+
/// pointers_to_members(representation method[, general purpose
6988+
/// representation]).
6989+
void ActOnPragmaMSPointersToMembers(PragmaMSPointersToMembersKind Kind,
6990+
SourceLocation PragmaLoc);
6991+
69736992
/// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
69746993
void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
69756994

‎clang/lib/AST/MicrosoftCXXABI.cpp

-8
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,6 @@ CXXRecordDecl::getMSInheritanceModel() const {
109109
return IA->getSemanticSpelling();
110110
}
111111

112-
void CXXRecordDecl::setMSInheritanceModel() {
113-
if (hasAttr<MSInheritanceAttr>())
114-
return;
115-
116-
addAttr(MSInheritanceAttr::CreateImplicit(
117-
getASTContext(), calculateInheritanceModel(), getSourceRange()));
118-
}
119-
120112
// Returns the number of pointer and integer slots used to represent a member
121113
// pointer in the MS C++ ABI.
122114
//

‎clang/lib/Parse/ParseDeclCXX.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
26202620
continue;
26212621
}
26222622

2623+
if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
2624+
HandlePragmaMSPointersToMembers();
2625+
continue;
2626+
}
2627+
26232628
// If we see a namespace here, a close brace was missing somewhere.
26242629
if (Tok.is(tok::kw_namespace)) {
26252630
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));

‎clang/lib/Parse/ParsePragma.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ void Parser::HandlePragmaOpenCLExtension() {
180180
}
181181
}
182182

183+
void Parser::HandlePragmaMSPointersToMembers() {
184+
assert(Tok.is(tok::annot_pragma_ms_pointers_to_members));
185+
Sema::PragmaMSPointersToMembersKind RepresentationMethod =
186+
static_cast<Sema::PragmaMSPointersToMembersKind>(
187+
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
188+
SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
189+
Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc);
190+
}
183191

184192

185193
// #pragma GCC visibility comes in two variants:
@@ -799,6 +807,99 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
799807
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
800808
}
801809

810+
/// \brief Handle '#pragma pointers_to_members'
811+
// The grammar for this pragma is as follows:
812+
//
813+
// <inheritance model> ::= ('single' | 'multiple' | 'virtual') '_inheritance'
814+
//
815+
// #pragma pointers_to_members '(' 'best_case' ')'
816+
// #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')'
817+
// #pragma pointers_to_members '(' inheritance-model ')'
818+
void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP,
819+
PragmaIntroducerKind Introducer,
820+
Token &Tok) {
821+
SourceLocation PointersToMembersLoc = Tok.getLocation();
822+
PP.Lex(Tok);
823+
if (Tok.isNot(tok::l_paren)) {
824+
PP.Diag(PointersToMembersLoc, diag::warn_pragma_expected_lparen)
825+
<< "pointers_to_members";
826+
return;
827+
}
828+
PP.Lex(Tok);
829+
const IdentifierInfo *Arg = Tok.getIdentifierInfo();
830+
if (!Arg) {
831+
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
832+
<< "pointers_to_members";
833+
return;
834+
}
835+
PP.Lex(Tok);
836+
837+
Sema::PragmaMSPointersToMembersKind RepresentationMethod;
838+
if (Arg->isStr("best_case")) {
839+
RepresentationMethod = Sema::PPTMK_BestCase;
840+
} else {
841+
if (Arg->isStr("full_generality")) {
842+
if (Tok.is(tok::comma)) {
843+
PP.Lex(Tok);
844+
845+
Arg = Tok.getIdentifierInfo();
846+
if (!Arg) {
847+
PP.Diag(Tok.getLocation(),
848+
diag::err_pragma_pointers_to_members_unknown_kind)
849+
<< Tok.getKind() << /*OnlyInheritanceModels*/ 0;
850+
return;
851+
}
852+
PP.Lex(Tok);
853+
} else if (Tok.is(tok::r_paren)) {
854+
// #pragma pointers_to_members(full_generality) implicitly specifies
855+
// virtual_inheritance.
856+
Arg = 0;
857+
RepresentationMethod = Sema::PPTMK_FullGeneralityVirtualInheritance;
858+
} else {
859+
PP.Diag(Tok.getLocation(), diag::err_expected_punc)
860+
<< "full_generality";
861+
return;
862+
}
863+
}
864+
865+
if (Arg) {
866+
if (Arg->isStr("single_inheritance")) {
867+
RepresentationMethod = Sema::PPTMK_FullGeneralitySingleInheritance;
868+
} else if (Arg->isStr("multiple_inheritance")) {
869+
RepresentationMethod = Sema::PPTMK_FullGeneralityMultipleInheritance;
870+
} else if (Arg->isStr("virtual_inheritance")) {
871+
RepresentationMethod = Sema::PPTMK_FullGeneralityVirtualInheritance;
872+
} else {
873+
PP.Diag(Tok.getLocation(),
874+
diag::err_pragma_pointers_to_members_unknown_kind)
875+
<< Arg << /*HasPointerDeclaration*/ 1;
876+
return;
877+
}
878+
}
879+
}
880+
881+
if (Tok.isNot(tok::r_paren)) {
882+
PP.Diag(Tok.getLocation(), diag::err_expected_rparen_after)
883+
<< (Arg ? Arg->getName() : "full_generality");
884+
return;
885+
}
886+
887+
PP.Lex(Tok);
888+
if (Tok.isNot(tok::eod)) {
889+
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
890+
<< "pointers_to_members";
891+
return;
892+
}
893+
894+
Token AnnotTok;
895+
AnnotTok.startToken();
896+
AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members);
897+
AnnotTok.setLocation(PointersToMembersLoc);
898+
AnnotTok.setAnnotationValue(
899+
reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod)));
900+
PP.EnterToken(AnnotTok);
901+
}
902+
802903
/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
803904
///
804905
/// The syntax is:

‎clang/lib/Parse/ParsePragma.h

+7
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ class PragmaDetectMismatchHandler : public PragmaHandler {
134134
Sema &Actions;
135135
};
136136

137+
class PragmaMSPointersToMembers : public PragmaHandler {
138+
public:
139+
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
140+
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
141+
Token &FirstToken);
142+
};
143+
137144
} // end namespace clang
138145

139146
#endif

‎clang/lib/Parse/ParseStmt.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
345345
ProhibitAttributes(Attrs);
346346
return ParseOpenMPDeclarativeOrExecutableDirective();
347347

348+
case tok::annot_pragma_ms_pointers_to_members:
349+
ProhibitAttributes(Attrs);
350+
HandlePragmaMSPointersToMembers();
351+
return StmtEmpty();
352+
348353
}
349354

350355
// If we reached this code, the statement must end in a semicolon.
@@ -820,6 +825,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
820825
case tok::annot_pragma_fp_contract:
821826
HandlePragmaFPContract();
822827
break;
828+
case tok::annot_pragma_ms_pointers_to_members:
829+
HandlePragmaMSPointersToMembers();
830+
break;
823831
default:
824832
checkForPragmas = false;
825833
break;

‎clang/lib/Parse/Parser.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
108108
PP.AddPragmaHandler(MSCommentHandler.get());
109109
MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(actions));
110110
PP.AddPragmaHandler(MSDetectMismatchHandler.get());
111+
MSPointersToMembers.reset(new PragmaMSPointersToMembers());
112+
PP.AddPragmaHandler(MSPointersToMembers.get());
111113
}
112114

113115
CommentSemaHandler.reset(new ActionCommentHandler(actions));
@@ -483,6 +485,8 @@ Parser::~Parser() {
483485
MSCommentHandler.reset();
484486
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
485487
MSDetectMismatchHandler.reset();
488+
PP.RemovePragmaHandler(MSPointersToMembers.get());
489+
MSPointersToMembers.reset();
486490
}
487491

488492
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
@@ -702,6 +706,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
702706
case tok::annot_pragma_openmp:
703707
ParseOpenMPDeclarativeDirective();
704708
return DeclGroupPtrTy();
709+
case tok::annot_pragma_ms_pointers_to_members:
710+
HandlePragmaMSPointersToMembers();
711+
return DeclGroupPtrTy();
705712
case tok::semi:
706713
// Either a C++11 empty-declaration or attribute-declaration.
707714
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),

‎clang/lib/Sema/Sema.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
7575
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
7676
CollectStats(false), CodeCompleter(CodeCompleter),
7777
CurContext(0), OriginalLexicalContext(0),
78-
PackContext(0), MSStructPragmaOn(false), VisContext(0),
78+
PackContext(0), MSStructPragmaOn(false),
79+
MSPointerToMemberRepresentationMethod(PPTMK_BestCase), VisContext(0),
7980
IsBuildingRecoveryCallExpr(false),
8081
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
8182
IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),

‎clang/lib/Sema/SemaAttr.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,13 @@ void Sema::ActOnPragmaDetectMismatch(StringRef Name, StringRef Value) {
287287
Consumer.HandleDetectMismatch(Name, Value);
288288
}
289289

290+
void Sema::ActOnPragmaMSPointersToMembers(
291+
PragmaMSPointersToMembersKind RepresentationMethod,
292+
SourceLocation PragmaLoc) {
293+
MSPointerToMemberRepresentationMethod = RepresentationMethod;
294+
ImplicitMSInheritanceAttrLoc = PragmaLoc;
295+
}
296+
290297
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
291298
SourceLocation PragmaLoc) {
292299

‎clang/lib/Sema/SemaDecl.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1963,7 +1963,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
19631963
NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
19641964
AttrSpellingListIndex);
19651965
else if (MSInheritanceAttr *IA = dyn_cast<MSInheritanceAttr>(Attr))
1966-
NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), AttrSpellingListIndex,
1966+
NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
1967+
AttrSpellingListIndex,
19671968
IA->getSemanticSpelling());
19681969
else if (isa<AlignedAttr>(Attr))
19691970
// AlignedAttrs are handled separately, because we need to handle all
@@ -12152,7 +12153,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1215212153

1215312154
if (const MSInheritanceAttr *IA = Record->getAttr<MSInheritanceAttr>())
1215412155
checkMSInheritanceAttrOnDefinition(cast<CXXRecordDecl>(Record),
12155-
IA->getRange(),
12156+
IA->getRange(), IA->getBestCase(),
1215612157
IA->getSemanticSpelling());
1215712158
}
1215812159

0 commit comments

Comments
 (0)